Merge "MS-VT: Add support that controls holding a video call"
diff --git a/Android.bp b/Android.bp
index 455634f..76e910f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -24,6 +24,7 @@
         "ims-common",
         "org.apache.http.legacy",
         "libprotobuf-java-lite",
+        "unsupportedappusage",
     ],
 
     static_libs: [
@@ -38,12 +39,15 @@
     ],
 
     srcs: [
+        ":framework-telephony-stack-shared-srcs",
         "src/**/*.java",
         "sip/src/**/*.java",
         "ecc/proto/**/*.proto",
         "src/com/android/phone/EventLogTags.logtags",
     ],
 
+    jarjar_rules: ":jarjar-rules-shared",
+
     resource_dirs: [
         "res",
         "sip/res",
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index f0fff9e..1d32288 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -36,7 +36,6 @@
     <protected-broadcast android:name="android.intent.action.DATA_STALL_DETECTED" />
     <protected-broadcast android:name="android.intent.action.SIM_STATE_CHANGED" />
     <protected-broadcast android:name="android.intent.action.NETWORK_SET_TIME" />
-    <protected-broadcast android:name="android.intent.action.NETWORK_SET_TIMEZONE" />
     <protected-broadcast android:name="com.android.internal.intent.action.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS" />
     <protected-broadcast android:name="android.intent.action.ACTION_MDN_STATE_CHANGED" />
     <protected-broadcast android:name="android.provider.Telephony.SPN_STRINGS_UPDATED" />
@@ -96,6 +95,9 @@
     <!-- For Vendor Debugging in Telephony -->
     <protected-broadcast android:name="android.telephony.action.ANOMALY_REPORTED" />
 
+    <!-- Allows granting runtime permissions to telephony related components. -->
+    <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS" />
+
     <uses-permission android:name="android.permission.BROADCAST_STICKY" />
     <uses-permission android:name="android.permission.CALL_PHONE" />
     <uses-permission android:name="android.permission.CALL_PRIVILEGED" />
@@ -159,6 +161,7 @@
     <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
     <uses-permission android:name="android.permission.MANAGE_APP_OPS_MODES" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
     <uses-permission android:name="android.permission.NETWORK_FACTORY" />
     <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
     <uses-permission android:name="android.permission.SET_PREFERRED_APPLICATIONS" />
@@ -171,7 +174,7 @@
     <!-- BIND_CARRIER_MESSAGING_SERVICE has been deprecated in favor of BIND_CARRIER_SERVICES. -->
     <uses-permission android:name="android.permission.BIND_CARRIER_MESSAGING_SERVICE" />
     <uses-permission android:name="android.permission.BIND_EUICC_SERVICE" />
-    <uses-permission android:name="com.android.permission.BIND_TELEPHONY_NETWORK_SERVICE" />
+    <uses-permission android:name="android.permission.BIND_TELEPHONY_NETWORK_SERVICE" />
     <uses-permission android:name="android.permission.BIND_CELL_BROADCAST_SERVICE" />
     <uses-permission android:name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" />
     <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 1321ace..22845e0 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -48,3 +48,5 @@
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/com.android.services.telephony.common_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/telephony-common.jar)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/ims-common.jar)
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..e75dcb0
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "TeleServiceTests",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    }
+  ]
+}
diff --git a/apex/Android.bp b/apex/Android.bp
new file mode 100644
index 0000000..86ebe3a
--- /dev/null
+++ b/apex/Android.bp
@@ -0,0 +1,28 @@
+apex {
+    name: "com.android.telephony",
+
+    manifest: "apex_manifest.json",
+
+    // optional. if unspecified, a default one is auto-generated
+    androidManifest: "AndroidManifest.xml",
+
+    java_libs: ["telephony-common", "ims-common"],
+    //apps: ["TeleService", "StkLib", "ONSLib"],
+    apps: ["StkLib"],
+
+    key: "com.android.telephony.key",
+    certificate: ":com.android.telephony.certificate",
+}
+
+apex_key {
+    name: "com.android.telephony.key",
+    public_key: "com.android.telephony.avbpubkey",
+    private_key: "com.android.telephony.pem",
+}
+
+android_app_certificate {
+    name: "com.android.telephony.certificate",
+    // This will use com.android.telephony.x509.pem (the cert) and
+    // com.android.telephony.pk8 (the private key)
+    certificate: "com.android.telephony",
+}
diff --git a/apex/AndroidManifest.xml b/apex/AndroidManifest.xml
new file mode 100644
index 0000000..a32ab33
--- /dev/null
+++ b/apex/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.telephony">
+    <!-- APEX does not have classes.dex -->
+    <application android:hasCode="false" />
+    <!-- Setting maxSdk to lock the module to R. minSdk is auto-set by build system -->
+    <uses-sdk
+        android:maxSdkVersion="30"
+        android:targetSdkVersion="30"
+    />
+</manifest>
\ No newline at end of file
diff --git a/apex/apex_manifest.json b/apex/apex_manifest.json
new file mode 100644
index 0000000..493d6fd
--- /dev/null
+++ b/apex/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.telephony",
+  "version": 1
+}
\ No newline at end of file
diff --git a/apex/com.android.telephony.avbpubkey b/apex/com.android.telephony.avbpubkey
new file mode 100644
index 0000000..cba14427
--- /dev/null
+++ b/apex/com.android.telephony.avbpubkey
Binary files differ
diff --git a/apex/com.android.telephony.pem b/apex/com.android.telephony.pem
new file mode 100644
index 0000000..19d8c05
--- /dev/null
+++ b/apex/com.android.telephony.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEAvEOU0eLO65uykCUYoLBXxjsIB7pCIXahtyIMYiGuUl6tnYb2
+gjPxsD9fNrqgdT+WgzHlfMPr4GqkT7prSI4/y9NglnFk2nAKZLQwiwtLOmm54Cnp
+OqqQZ9+g4MvA2rsrmstJ/Pdu4t+9Bv9bZHYLEPCW4LV1v5S2jY7ie/C+SbZm8yFz
+X9RgTX7loH7oSNDqvVMRUeyrlH3gRHxPMQxIMfLMro1NCfkA4q8QnwPpM2+YEBf0
+kktXkvbfJUB0Ywo6BCVAoqxkghNQQTLBuBDFnho13gQSMOLu8C62pzdAyPm/n5Yv
+aqEdmmGkBsy2qiHTiRuiWWl9aGDhd0U6e+hYK4OM3ISDQiTr5OuraIKt8EH7jo8H
+Zb/WqJFygOq5RqXmAvbtq+eBAgLlUNAl5F9RwLU6zPTREsSGG/g1fqUSD4ZS2qHt
+d9aBdSepvL4xDCg9BDTFMt4Xjc83hk+v7nIIPB4cayA9s2kgjXwjZhiMOJuoNMmr
+Wu2GP9zw37WmUF5jXKgICVtoq//qofA3KA+YZ8NcmPRmeBzCEks5fCAZN64AIh5l
+vi8pPv+s8lbhGui/dkgJAGoMWKwukMZZDxTFfgbPU74yIWUpoiXGEv+0WPsOyxKe
+HEC0uXL6h6HtTaxTTyk9OJp1Z12ih2CdHmoK8aHeL1ND+YXxko4rcVyJGvcCAwEA
+AQKCAgAve1gAa5TGhZlOk5yXgoJQw7itwkNFj1cQCi1XXqlJqwlcrppjklhFnGYW
+NpGboLMEWcRIaF2IVz0jwp+mSAI9FQ3KQ8Us9o8YgP2xQ+LwU5QGvmtNWZFcMWGw
+8JKuWACSZO0/OOSlocpaBnN1bfQyjItxFzMgY5B7OWtT2Q8VJkTm0yv3Img7g2LE
+zN0m6FIb9+RpZiiMJgc3HqcWdsOKnXMUHx0sA7o+cereQC1DxMR0YqZTc18d+Nek
+3JG+HOku/HpFzPb4e4iFORj0pH5C9tdZLGuuGr4qo417tQrI5Xx38nf5C7OcqT2m
+XWFAnZFthiO3K0zu02hqHXK3p4z81aerzOAFHQP9Dvw0LrEevhMS7POwnoBMWIYT
+j2oJAKf84AIt+URNxRMcOH4Vs8133ZJxesotYzEdZBN4KBukCC+MzLtkJ3C3vLSu
+PPlwYfS0T/wMLBlQRfGM2pZbuldc4Th+VuE8lvDIvmZKxUXdAh/OkTJRt95SSpFQ
+PZy9NauagIaDyE08z3vgiYUH/498piibXiv4ox9puyfDI30W7VlZA9NBV7UBhkcV
+vxmop3U4KJdI0dcwB/8oQao/eM8Bk8TOI58Ux/gM+7tLM+pzeIPlKsZ3GWjZYyZi
+Fds7JdprR2AljUoKXAGA3G2IejhiB6VSivR8IRLwdWZSAaM9iQKCAQEA512QfnYR
+MDjYzUBYySHANVFi09q3taoYJ1Ovq4w3YnC4Yy6OM1rI1g55mhzGGnrQhC8//Lwy
+v9fxhxEQkx8rY40KJRizfc28l3gIFzF+/mP5DqUQiVZQBiAm0m0y3LA1xTCRxyc/
+yLWCodFOojcg8H3vxDUiL+80wLRX/zXmUHjhGmg+sZVtuWTVpgdFEGR1guVAoXPM
+t6p9+Zpr+yhURRuce7IfjVxIXtjzaZ6fglCYSnakhxvBMWvvhhD2Sx60bl0sBpsT
+oj4VZmd7i01bde1H2BlJ9ca23uGPylvmC+kVFVoqnMv7dZuhHgQY06zg+zts8Grm
+mVcTa5xKtEr2FQKCAQEA0E8t9/XV6tEH5BoiZ6SLIYeh+yk/h8hQKGn+lnzcywon
+L/EEtvqzoeIkbLATOk4ffbiYtI86GxldPUp293ups9rJCJdb7fIahJJd4Pl9d9QF
+dEWkuMC9btyBq0WjvJLIVxKLcBv9NAMnfLYIWk4OfAXQ2Kgv4OrYmxqtLdnzqIT0
+4jgQcHkaDbPIBkOAfAcyy6b6TNsdhiR/ojZ/3s7e0YpUhUkvGqHPeGkg827fznui
+mOSvuIC1eg92Kpsv/NzZkSkhh+Y4yT3mXTPkdRrIoRiwfUsBx9c3CUB1bhMlqYdP
+p9IwfcDYPmPIWqD/5EIm5CIFTh/qFuJuB/RP1xr72wKCAQEAm6BZGGdsqmYilvWI
+g0o7kuG6u0xstDrE4nctPBQmEQZHURe4uRyA6VN1Qk/GhXtFFRT/Uo55CIhFw5eb
+8YpO0jjFsSxLV/zytWQc9RTrGky+87XeSLMRQv2Pf43KX537nTdNZ4ukIOrPAu/a
+l8zDUGE1zWH8LAgYEON+KYHk+Q5GRFAIk8UyuDj2aSaMszkPvktczP0qoASDlkjk
+B14aSR4IhT/Mb3a6i2odWVdEbhCuT7A8fVETA55Z0HFKaj8uGOp9ObhIXaKrHGXR
+OWOAePNxlw9zq2nOCl/pK7HjLPHMp78t2Khw7awQlTMmTAQGlZdkcNdHY6+ptYG8
+0kd1/QKCAQAaosVB+5FK4UedByp3DjcsJmez8eZJundlc4g2PekNnVK9cpgjvZLS
+lFQMAcezoOGt9biw/c90P54IhEkKBCoC8WrbSl9a4aY6ZWzTo5NDizzXTUBuz1Zp
+opCCEfmJ10r+t0RVJX8O84hNDgmrYme/vA6kZX0ZyW3BB3w1bLUXS0j01C5l81Y9
+gkuFYYRAV7tLByLiSPJRgMFBQK7BErqzGHkOQflf8mjRAMBR4E+F25FC85r0gKCz
+5t45PHa6YpL/WL8M3YdNVDjsmgIQZ0hYMQwAOWMU5pQG/tMFLDWYo9CvqNTCf7Im
+6CNqU0PlMABBE4iSIMqR+ooPQlIjMzQZAoIBAQC9JulZdQJzjZSI5tBj+zPScJJQ
+s/+sRfQBy7SalPtc+oLYBP2Js9c1JsR4Dk2vC3V5z7BaL4Lg4YcFVRcz9B4yUVRm
+BL/E34XGLfn5KBI8NeqIvHiivvlAPgoHwHAVsqtE35E2sYjOYbnn1FEaNm6EKiL3
+Dv1auVdLlP3jALJIEwHPzc2ZOc/Sh/LolfajR427j5YlgbMAk5DdXuxz7t9qEcyk
+Nc8HFaoXiBP1jK+L5C4mVvGeI9xghNoJXhNywEmMa2Shab0pmtOMQWuvNMQa3gRC
+OKbaM3A6zjvAl3rjFRBrGORqbu1E/InLOSXWuB8knYVf8LkWEDRjOHqMO3pJ
+-----END RSA PRIVATE KEY-----
diff --git a/apex/com.android.telephony.pk8 b/apex/com.android.telephony.pk8
new file mode 100644
index 0000000..b15a884
--- /dev/null
+++ b/apex/com.android.telephony.pk8
Binary files differ
diff --git a/apex/com.android.telephony.x509.pem b/apex/com.android.telephony.x509.pem
new file mode 100644
index 0000000..8b45823
--- /dev/null
+++ b/apex/com.android.telephony.x509.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGKTCCBBGgAwIBAgIUCmopA1YmjspwjjHHjmtsDPqxBxgwDQYJKoZIhvcNAQEL
+BQAwgaIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
+b2lkMR4wHAYDVQQDDBVjb20uYW5kcm9pZC50ZWxlcGhvbnkxIjAgBgkqhkiG9w0B
+CQEWE2FuZHJvaWRAYW5kcm9pZC5jb20wIBcNMTkxMjA0MDAzNjAxWhgPNDc1NzEw
+MzAwMDM2MDFaMIGiMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEW
+MBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UE
+CwwHQW5kcm9pZDEeMBwGA1UEAwwVY29tLmFuZHJvaWQudGVsZXBob255MSIwIAYJ
+KoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEA4qQYe8S6yte4MUDF2/JBUulJLF15CdnALkDJuGYLRom2
+DxRpq2/IqX8gpwVfZCfVjtthKGMhsdLW9gI+oKck0eVB7Q2cU/WO+1Cr9cuKuT6B
+cfJUck125gRGmowWZomDXv1to6ZrGgqBlVGA546w3CNGXW/PoKr8im+xLEgD0TPA
+3jJCbxt2v2IDjMwPChHOF57y9wRkXN5aJHgwIvayReVy3Cko/rJOuPnNo2kLKI5u
+qfM4NovYNAzKbHHPCNzqhySoh2H0iTmHLby5bvXYh32ooGPmxrP6q8PubeNb+Xfc
+yY33tE74ityiqu/2FDuK2iZyL8EZkEWHbX4ddt/JREda1Mcnt95TUudqA28xHgC4
+wRYXLUADvKDVWOYu/ydWBes1iu7ZsEhy8oFdECsZGRQm2BkdmWAsMPUXRWeiaCQ4
+GFfpB38UPczY5GTgYwKAK3mmY5EeBKRu/hFMCfYGJvio2rUujRzIGOd6ovk+G/74
+Eqdbsphrkr6+UOCUrNOYUD0j7kDHVVDiWMoeKL6Qb+dFcewdDO1rRbZv8ZeExf6l
+vacfKKcEE+wls8jqof/y7cu+McGEn4R8+KKiRDcDQqLvZN4Q+CCtNRLiXA2KdrkB
+hKfhnTBBYfDNZA1WOhGrKM+Yb97ObgAgf2HuhZ2F40F3dRZ6w8yaURXAjkdCqycC
+AwEAAaNTMFEwHQYDVR0OBBYEFDCf58Ogbx07WK+hWEylNMxKYrj6MB8GA1UdIwQY
+MBaAFDCf58Ogbx07WK+hWEylNMxKYrj6MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggIBABoGWqoOfPBsXFYzP7aNhywhuCr6ddjAi3ss9vwod6JuVuVg
+Inuw1i/qPb/bO1JFEwYVH3w0JASMwzIl9h5sQv++z0P+cWsLW02AXyszb0jGD3CI
+ni/irO5PO0DdaTSHQWc8DEv0293EcqpKWmQDQ2XWH19rJ5f+Gx1046sFlUi633D2
+sFO5dG94pCtT/TcqwwkeEwA6cV2Re8F1AW8elal3sINBU5MI/OJ3GQDe+pqp9VTg
+xIEQfZ9oP6Ewl6Ect+M2hVG5X4mCk9HQL7aSuPKo2Ej6l3Xq4aQYlpO4wOVZgCJC
+chMbdAn2pjuk8+mDSR39hdIusOgr7zLZscmaGKyoxVz9KVNwd/mmu+9/mftGfYae
+RomF15hVnkhZAw21fSnhKry62+DuKt2WIyu5LqvTvRxFs0Hvoy3wrQY/oruHlgk1
+J1v1rXm3ZTrh2qv1XG8mOdTegurEvjkYQm0E38jdlkhByIHmhDdBARX2Aeb7Lrd8
+9k/7tr9+58+45punZBBMX6iW1xfwaCDF8xfZrrC96azXP6Kv/JZTxbfNm/dqHyKK
+zM2WhELaoJg7uFO9TC5eMsnBQzDoYXsr3Mu7nC7V1Bs/D7jYmFG0dG0LQJwUUGr1
+WqJT4LB0BMnzNrMH1hTQTBVYDlfn7c6fnihNBOWQt72x2GGFQsGAMUWb7pxC
+-----END CERTIFICATE-----
diff --git a/res/layout/band_mode.xml b/res/layout/band_mode.xml
new file mode 100644
index 0000000..b43dd1d
--- /dev/null
+++ b/res/layout/band_mode.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:padding="4dip"
+              android:gravity="center_horizontal"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content">
+
+    <ListView android:id="@+id/band"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:textSize="7sp">
+    </ListView>
+
+</LinearLayout>
diff --git a/res/layout/radio_info.xml b/res/layout/radio_info.xml
new file mode 100644
index 0000000..40c2e53
--- /dev/null
+++ b/res/layout/radio_info.xml
@@ -0,0 +1,414 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/Settings/assets/res/any/layout/radio_info.xml
+**
+** Copyright 2006, 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.
+*/
+-->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout style="@style/info_layout"
+        android:descendantFocusability="beforeDescendants"
+        android:focusableInTouchMode="true">
+
+        <!-- Phone index -->
+        <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/phone_index_label"
+                style="@style/info_label"
+                />
+
+        <Spinner android:id="@+id/phoneIndex"
+                 android:layout_width="match_parent"
+                 android:layout_height="wrap_content"
+                />
+
+        <!-- IMEI -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_imei_label" style="@style/info_label" />
+            <TextView android:id="@+id/imei" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- Phone Number -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_phone_number_label" style="@style/info_label" />
+            <TextView android:id="@+id/number" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- Subscription ID -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_subid" style="@style/info_label" />
+            <TextView android:id="@+id/subid" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- Default data subscription -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_dds" style="@style/info_label" />
+            <TextView android:id="@+id/dds" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- IMSI -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_imsi_label" style="@style/info_label" />
+            <TextView android:id="@+id/imsi" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- Network Identifier -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_current_network_label" style="@style/info_label" />
+            <TextView android:id="@+id/operator" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- Roaming -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_roaming_label" style="@style/info_label" />
+            <TextView android:id="@+id/roaming" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- Data Service Status -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_gprs_service_label" style="@style/info_label" />
+            <TextView android:id="@+id/gprs" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- Data Network Type -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_data_network_type_label" style="@style/info_label" />
+            <TextView android:id="@+id/data_network" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- Voice Service Status -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_gsm_service_label" style="@style/info_label" />
+            <TextView android:id="@+id/gsm" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- Voice Network Type -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_voice_network_type_label" style="@style/info_label" />
+            <TextView android:id="@+id/voice_network" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- Signal Strength -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_signal_strength_label" style="@style/info_label" />
+            <TextView android:id="@+id/dbm" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- Link Bandwidth -->
+        <LinearLayout style="@style/RadioInfo_entry_layout" android:orientation="horizontal">
+            <TextView android:text="@string/radio_info_dl_kbps" style="@style/info_label" />
+            <TextView android:id="@+id/dl_kbps" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- Link Bandwidth -->
+        <LinearLayout style="@style/RadioInfo_entry_layout" android:orientation="horizontal">
+            <TextView android:text="@string/radio_info_ul_kbps" style="@style/info_label" />
+            <TextView android:id="@+id/ul_kbps" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- Physical Channel Config -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_phy_chan_config" style="@style/info_label" />
+            <TextView android:id="@+id/phy_chan_config" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- Horizontal Rule -->
+        <View
+            android:layout_width="fill_parent"
+            android:layout_height="1dip"
+            android:background="?android:attr/listDivider" />
+
+        <!-- Preferred Network Type -->
+        <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/radio_info_set_perferred_label"
+                style="@style/info_label"
+                />
+
+        <Spinner android:id="@+id/preferredNetworkType"
+                 android:layout_width="match_parent"
+                 android:layout_height="wrap_content"
+                />
+
+        <!-- Horizontal Rule -->
+        <View
+            android:layout_width="fill_parent"
+            android:layout_height="1dip"
+            android:background="?android:attr/listDivider" />
+
+        <!-- Radio Power -->
+        <Switch android:id="@+id/radio_power"
+                android:textSize="14sp"
+                android:layout_marginTop="8dip"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/radio_info_radio_power"/>
+
+        <!-- VoLTE provisioned -->
+        <Switch android:id="@+id/volte_provisioned_switch"
+                android:textSize="14sp"
+                android:layout_marginTop="8dip"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/volte_provisioned_switch_string"/>
+
+        <!-- VT provisioned -->
+        <Switch android:id="@+id/vt_provisioned_switch"
+                android:textSize="14sp"
+                android:layout_marginTop="8dip"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/vt_provisioned_switch_string"/>
+
+        <!-- Wifi Calling provisioned -->
+        <Switch android:id="@+id/wfc_provisioned_switch"
+                android:textSize="14sp"
+                android:layout_marginTop="8dip"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/wfc_provisioned_switch_string"/>
+
+        <!-- EAB/Presence provisioned -->
+        <Switch android:id="@+id/eab_provisioned_switch"
+                android:textSize="14sp"
+                android:layout_marginTop="8dip"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/eab_provisioned_switch_string"/>
+
+        <!-- Horizontal Rule -->
+        <View
+            android:layout_width="fill_parent"
+            android:layout_height="1dip"
+            android:background="?android:attr/listDivider" />
+
+        <!-- Enable/Disable CBRS data -->
+        <Switch android:id="@+id/cbrs_data_switch"
+                android:textSize="14sp"
+                android:layout_marginTop="8dip"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/cbrs_data_switch_string" />
+
+        <!-- Switch between SSSS(single sim single standby) and DSDS(dual sim dual standby). -->
+        <Switch android:id="@+id/dsds_switch"
+                android:textSize="14sp"
+                android:layout_marginTop="8dip"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/dsds_switch_string" />
+
+        <!-- Horizontal Rule -->
+        <View
+            android:layout_width="fill_parent"
+            android:layout_height="1dip"
+            android:background="?android:attr/listDivider" />
+
+        <!-- Ping stats -->
+        <Button android:id="@+id/ping_test"
+                android:textSize="14sp"
+                android:layout_marginTop="8dip"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/ping_test_label"
+                />
+ 
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_ping_hostname_v4" style="@style/info_label" />
+            <TextView android:id="@+id/pingHostnameV4" style="@style/info_value" />
+        </LinearLayout>
+
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_ping_hostname_v6" style="@style/info_label" />
+            <TextView android:id="@+id/pingHostnameV6" style="@style/info_value" />
+        </LinearLayout>
+
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_http_client_test" style="@style/info_label" />
+            <TextView android:id="@+id/httpClientTest" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- Horizontal Rule -->
+        <View
+            android:layout_width="fill_parent"
+            android:layout_height="1dip"
+            android:background="?android:attr/listDivider" />
+
+        <!-- PPP Sent -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_ppp_sent_label"
+                style="@style/info_label" />
+            <TextView android:id="@+id/sent" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- PPP Received -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_ppp_received_label"
+                style="@style/info_label" />
+            <TextView android:id="@+id/received" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- PPP Sent since last received -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_ppp_resets_label"
+                style="@style/info_label" />
+            <TextView android:id="@+id/sentSinceReceived" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- Horizontal Rule -->
+        <View
+            android:layout_width="fill_parent"
+            android:layout_height="1dip"
+            android:background="?android:attr/listDivider" />
+
+        <!-- Call Status -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_call_status_label" style="@style/info_label" />
+            <TextView android:id="@+id/call" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- Message Waiting Indicator -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_message_waiting_label" style="@style/info_label" />
+            <TextView android:id="@+id/mwi" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- Call Forwarding Indicator -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_call_redirect_label" style="@style/info_label" />
+            <TextView android:id="@+id/cfi" style="@style/info_value" />
+        </LinearLayout>
+
+        <!-- Horizontal Rule -->
+        <View
+            android:layout_width="fill_parent"
+            android:layout_height="1dip"
+            android:background="?android:attr/listDivider" />
+
+        <!-- CellInfoListRate Selection -->
+        <!-- Location -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_signal_location_label" style="@style/info_label" />
+            <TextView android:id="@+id/location" style="@style/info_value" />
+        </LinearLayout>
+
+        <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/radio_info_cell_info_refresh_rate"
+                style="@style/info_label"
+                />
+
+        <Spinner android:id="@+id/cell_info_rate_select"
+                 android:layout_width="match_parent"
+                 android:layout_height="wrap_content"
+                />
+
+        <!-- CellInfo -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:text="@string/radio_info_cellinfo_label"
+                      style="@style/info_label" />
+        </LinearLayout>
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <TextView android:id="@+id/cellinfo"
+                      style="@style/info_value"
+                      android:minHeight="300dip"
+                      android:textSize="12sp" />
+        </LinearLayout>
+
+        <!-- Horizontal Rule -->
+        <View
+            android:layout_width="fill_parent"
+            android:layout_height="1dip"
+            android:background="?android:attr/listDivider" />
+
+        <!-- Launch OEM-specific Info/Settings Activity (if any) -->
+        <!-- Carrier Provisioning -->
+        <LinearLayout style="@style/RadioInfo_entry_layout"
+                      android:orientation="horizontal" >
+            <Button android:id="@+id/carrier_provisioning"
+                    android:layout_marginTop="8dip"
+                    android:layout_weight="1"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:text="@string/carrier_provisioning"
+                    android:textSize="14sp"/>
+            <Button android:id="@+id/trigger_carrier_provisioning"
+                    android:layout_marginTop="8dip"
+                    android:layout_weight="1"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:text="@string/trigger_carrier_provisioning"
+                    android:textSize="14sp"/>
+            <Button android:id="@+id/oem_info"
+                    android:layout_marginTop="8dip"
+                    android:layout_weight="1"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:text="@string/oem_radio_info_label"
+                    android:textSize="14sp"/>
+        </LinearLayout>
+
+        <!-- SMSC -->
+        <RelativeLayout android:layout_width="match_parent"
+                        android:layout_height="wrap_content">
+            <TextView android:id="@+id/smsc_label"
+                      android:text="@string/radio_info_smsc_label"
+                      android:layout_alignBaseline="@+id/update_smsc"
+                      style="@style/info_label" />
+            <Button android:id="@+id/refresh_smsc"
+                    android:textSize="14sp"
+                    android:layout_marginTop="8dip"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/radio_info_smsc_refresh_label"
+                    android:layout_alignParentEnd="true"
+                    />
+            <Button android:id="@+id/update_smsc"
+                    android:textSize="14sp"
+                    android:layout_marginTop="8dip"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/radio_info_smsc_update_label"
+                    android:layout_toStartOf="@+id/refresh_smsc"
+                    android:layout_alignBaseline="@+id/refresh_smsc"
+                    />
+            <EditText android:id="@+id/smsc"
+                      style="@style/form_value"
+                      android:layout_alignBaseline="@+id/refresh_smsc"
+                      android:layout_toStartOf="@id/update_smsc"
+                      android:layout_toEndOf="@id/smsc_label" />
+        </RelativeLayout>
+
+        <!-- Test setting to ignore bad DNS, useful in lab environments -->
+        <LinearLayout style="@style/RadioInfo_entry_layout">
+            <Button android:id="@+id/dns_check_toggle"
+                    android:textSize="14sp"
+                    android:layout_marginTop="8dip"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/radio_info_toggle_dns_check_label"
+                    />
+            <TextView android:id="@+id/dnsCheckState" style="@style/info_value" />
+        </LinearLayout>
+
+
+    </LinearLayout>
+</ScrollView>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 689e239..b97ef10 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1776,7 +1776,7 @@
     <!-- Call barring settings screen, change password -->
     <string name="call_barring_change_pwd_description">Change call barring password</string>
     <!-- Call barring settings screen, not possible to change call barring password -->
-    <string name="call_barring_change_pwd_description_disabled">Cannot change call barring password.</string>
+    <string name="call_barring_change_pwd_description_disabled">Cannot change call barring password</string>
     <!-- Call barring settings screen, change password -->
     <string name="call_barring_pwd_not_match">Passwords do not match</string>
     <!-- Call barring settings screen, change password -->
@@ -1890,4 +1890,209 @@
     <string name="supp_service_over_ut_precautions_roaming_dual_sim">To use <xliff:g id="supp service">%1$s</xliff:g>, make sure mobile data and data roaming are turned on for SIM <xliff:g id="sim number">%2$d</xliff:g>. You can change these in mobile network settings.</string>
     <!-- supplementary services over ut precaution exit dialog choice -->
     <string name="supp_service_over_ut_precautions_dialog_dismiss">Dismiss</string>
+
+    <!-- Data Connection Enable. Only shown in diagnostic screen, so precise translation is not needed. -->
+    <string name="radio_info_data_connection_enable">Enable Data Connection</string>
+    <!-- Data Connection Disable. Only shown in diagnostic screen, so precise translation is not needed. -->
+    <string name="radio_info_data_connection_disable">Disable Data Connection</string>
+
+    <!-- VoLTE provisioning flag on. Only shown in diagnostic screen, so precise translation is not needed. -->
+    <string name="volte_provisioned_switch_string">VoLTE Provisioned</string>
+
+    <!-- Video calling provisioning flag on. Only shown in diagnostic screen, so precise translation is not needed. -->
+    <string name="vt_provisioned_switch_string">Video Calling Provisioned</string>
+
+    <!-- Wifi Calling provisioning flag on. Only shown in diagnostic screen, so precise translation is not needed. -->
+    <string name="wfc_provisioned_switch_string">Wifi Calling Provisioned</string>
+
+    <!-- EAB provisioning flag on. Only shown in diagnostic screen, so precise translation is not needed. -->
+    <string name="eab_provisioned_switch_string">EAB/Presence Provisioned</string>
+
+    <!-- Cbrs enable disable flag. Only shown in diagnostic screen, so precise translation is not needed -->
+    <string name="cbrs_data_switch_string">Cbrs Data</string>
+
+    <!-- Dsds enable/disable flag. Only shown in diagnostic screen, so precise translation is not needed, [CHAR LIMIT=none] -->
+    <string name="dsds_switch_string">Enable DSDS</string>
+
+    <!-- UI debug setting: Enable/Disable DSDS [CHAR LIMIT=none] -->
+    <string name="dsds_dialog_title">Restart Device?</string>
+
+    <!-- UI debug setting: Enable/Disable DSDS [CHAR LIMIT=none] -->
+    <string name="dsds_dialog_message">You need to restart your device to change this setting.</string>
+
+    <!-- UI debug setting: Enable/Disable DSDS [CHAR LIMIT=none] -->
+    <string name="dsds_dialog_confirm">Restart</string>
+
+    <!-- UI debug setting: Enable/Disable DSDS [CHAR LIMIT=none] -->
+    <string name="dsds_dialog_cancel">Cancel</string>
+
+    <!-- Title for controlling on/off for Mobile phone's radio power. Only shown in diagnostic screen, so precise translation is not needed. -->
+    <string name="radio_info_radio_power">Mobile Radio Power</string>
+
+    <!-- Phone Info screen. Menu item label.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_menu_viewADN">View SIM Address Book</string>
+    <!-- Phone Info screen. Menu item label.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_menu_viewFDN">View Fixed Dialing Numbers</string>
+    <!-- Phone Info screen. Menu item label.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_menu_viewSDN">View Service Dialing Numbers</string>
+    <!-- Phone Info screen. Menu item label.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_menu_getIMS">IMS Service Status</string>
+
+    <!-- Phone Info screen. IMS Registration Title.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_ims_reg_status_title">IMS Status</string>
+
+    <!-- Phone Info screen. IMS Status - Registered.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_ims_reg_status_registered">Registered</string>
+    <!-- Phone Info screen. Ims Status - Unregistered.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_ims_reg_status_not_registered">Not Registered</string>
+
+    <!-- Phone Info screen. Ims Feature Status label.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_ims_feature_status_available">Available</string>
+    <!-- Phone Info screen. Ims Feature status label.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_ims_feature_status_unavailable">Unavailable</string>
+
+    <!-- Phone Info screen. IMS Registration.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_ims_reg_status">IMS Registration: <xliff:g id="status" example="registered">%1$s</xliff:g>\u000AVoice over LTE: <xliff:g id="availability" example="available">%2$s</xliff:g>\u000AVoice over WiFi: <xliff:g id="availability" example="available">%3$s</xliff:g>\u000AVideo Calling: <xliff:g id="availability" example="available">%4$s</xliff:g>\u000AUT Interface: <xliff:g id="availability" example="available">%5$s</xliff:g></string>
+
+    <!-- Phone Info screen. Status label.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_service_in">In Service</string>
+    <!-- Phone Info screen. Status label.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_service_out">Out of Service</string>
+    <!-- Phone Info screen. Status label.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_service_emergency">Emergency Calls Only</string>
+    <!-- Phone Info screen. Status label.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_service_off">Radio Off</string>
+
+    <!-- Phone Info screen. Status label.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_roaming_in">Roaming</string>
+    <!-- Phone Info screen. Status label.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_roaming_not">Not Roaming</string>
+
+    <!-- Phone Info screen. Status label.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_phone_idle">Idle</string>
+    <!-- Phone Info screen. Status label.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_phone_ringing">Ringing</string>
+    <!-- Phone Info screen. Status label.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_phone_offhook">Call in Progress</string>
+
+    <!-- Phone Info screen. Status label.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_data_disconnected">Disconnected</string>
+    <!-- Phone Info screen. Status label.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_data_connecting">Connecting</string>
+    <!-- Phone Info screen. Status label.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_data_connected">Connected</string>
+    <!-- Phone Info screen. Status label.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_data_suspended">Suspended</string>
+
+    <!-- Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_unknown">Unknown</string>
+    <!-- Phone Info screen. Units shown after a value.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_display_packets">pkts</string>
+    <!-- Phone Info screen. Units shown after a value.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_display_bytes">bytes</string>
+    <!-- Phone Info screen. Units shown after a value.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_display_dbm">dBm</string>
+    <!-- Phone Info screen. Units shown after a value.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_display_asu">asu</string>
+    <!-- Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_lac">LAC</string>
+    <!-- Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radioInfo_cid">CID</string>
+
+
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_subid">Current subId:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_dds">SubId of default data SIM:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_dl_kbps">DL Bandwidth (kbps):</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_ul_kbps">UL Bandwidth (kbps):</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_signal_location_label">Cell Location Info (deprecated):</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_phy_chan_config">LTE Physical Channel Configuration:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_cell_info_refresh_rate">Cell Info Refresh Rate:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_cellinfo_label">All Cell Measurement Info:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_gprs_service_label">Data Service:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_roaming_label">Roaming:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_imei_label">IMEI:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, DO NOT TRANSLATE. -->
+    <string name="radio_info_imsi_label">IMSI:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_call_redirect_label">Call Redirect:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_ppp_resets_label">Number of PPP Reset Since Boot:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_current_network_label">Current Network:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_ppp_received_label">Data Received:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_gsm_service_label">Voice Service:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_signal_strength_label">Signal Strength:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_call_status_label">Voice Call Status:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_ppp_sent_label">Data Sent:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_message_waiting_label">Message Waiting:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_phone_number_label">Phone Number:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_band_mode_label">Select Radio Band</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_voice_network_type_label">Voice Network Type:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_data_network_type_label">Data Network Type:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="phone_index_label">Select phone index</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_set_perferred_label">Set Preferred Network Type:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_ping_hostname_v4">Ping Hostname(www.google.com) IPv4:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_ping_hostname_v6">Ping Hostname(www.google.com) IPv6:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_http_client_test">HTTP Client Test:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="ping_test_label">Run Ping Test</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_smsc_label">SMSC:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_smsc_update_label">Update</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_smsc_refresh_label">Refresh</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_toggle_dns_check_label">Toggle DNS Check</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="oem_radio_info_label">OEM-specific Info/Settings</string>
+
+    <!-- Band Mode Selection -->
+    <!-- Band mode screen.  Title of activity. -->
+    <string name="band_mode_title">Set Radio Band Mode</string>
+    <!-- Band mode screen.  Loading message. -->
+    <string name="band_mode_loading">Loading Band List\u2026</string>
+    <!-- Band mode screen. Button caption to set the bandmode. -->
+    <string name="band_mode_set">Set</string>
+    <!-- Band mode screen. Status message when unsuccessful. -->
+    <string name="band_mode_failed">Unsuccessful</string>
+    <!-- Band mode screen. Statusm essage when successful. -->
+    <string name="band_mode_succeeded">Successful</string>
+
+    <!-- The title of the activity to see phone info -->
+    <string name="phone_info_label" product="tablet">Tablet info</string>
+    <!-- The title of the activity to see phone info -->
+    <string name="phone_info_label" product="default">Phone info</string>
+
+    <!-- Carrier Provisioning Info [CHAR LIMIT=NONE] -->
+    <string name="carrier_provisioning">Carrier Provisioning Info</string>
+    <!-- Trigger Carrier Provisioning [CHAR LIMIT=NONE] -->
+    <string name="trigger_carrier_provisioning">Trigger Carrier Provisioning</string>
+
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index fc95803..e95142b 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -45,6 +45,23 @@
         <item name="android:layout_height">wrap_content</item>
     </style>
 
+    <style name="RadioInfo_entry_layout">
+        <item name="android:orientation">horizontal</item>
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+    </style>
+
+    <style name="info_value">
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:textAppearance">@style/TextAppearance.info_value</item>
+    </style>
+
+    <style name="form_value">
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:layout_width">match_parent</item>
+    </style>
+
     <style name="TextAppearance" parent="android:TextAppearance">
     </style>
 
@@ -53,6 +70,11 @@
         <item name="android:textStyle">bold</item>
     </style>
 
+    <style name="TextAppearance.info_value">
+        <item name="android:textSize">14sp</item>
+        <item name="android:textStyle">normal</item>
+    </style>
+
     <!-- Preference Style for the phone number preferences -->
     <style name="EditPhoneNumberPreference">
         <item name="enableButtonText">@string/enable</item>
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index e5e02fa..3f57cae 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -19,10 +19,12 @@
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
@@ -110,6 +112,50 @@
      * Click Listeners, handle click based on objects attached to UI.
      */
 
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            log("onReceive: " + intent.getAction());
+
+            if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(intent.getAction())) {
+                log("ACTION_AIRPLANE_MODE_CHANGED");
+
+                boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
+                handleAirplaneModeChange(isAirplaneModeOn);
+            }
+        }
+    };
+
+    private void handleAirplaneModeChange(boolean isAirplaneModeOn) {
+        PersistableBundle b = null;
+        if (mSubscriptionInfoHelper.hasSubId()) {
+            b = PhoneGlobals.getInstance().getCarrierConfigForSubId(
+                    mSubscriptionInfoHelper.getSubId());
+        } else {
+            b = PhoneGlobals.getInstance().getCarrierConfig();
+        }
+
+        if (b != null && b.getBoolean(
+                CarrierConfigManager.KEY_DISABLE_SUPPLEMENTARY_SERVICES_IN_AIRPLANE_MODE_BOOL)) {
+            PreferenceScreen preferenceScreen = getPreferenceScreen();
+            Preference callForwarding = preferenceScreen.findPreference(
+                    GsmUmtsCallOptions.CALL_FORWARDING_KEY);
+            Preference callBarring = preferenceScreen.findPreference(
+                    GsmUmtsCallOptions.CALL_BARRING_KEY);
+            Preference additional = preferenceScreen.findPreference(
+                    GsmUmtsCallOptions.ADDITIONAL_GSM_SETTINGS_KEY);
+            if (callForwarding != null) {
+                callForwarding.setEnabled(!isAirplaneModeOn);
+            }
+            if (callBarring != null) {
+                callBarring.setEnabled(!isAirplaneModeOn);
+            }
+            if (additional != null) {
+                additional.setEnabled(!isAirplaneModeOn);
+            }
+        }
+    }
+
     // Click listener for all toggle events
     @Override
     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
@@ -266,6 +312,7 @@
     protected void onPause() {
         super.onPause();
         listenPhoneState(false);
+        unregisterReceiver(mReceiver);
 
         // Remove callback for provisioning changes.
         try {
@@ -378,6 +425,10 @@
         } catch (ImsException e) {
             Log.w(LOG_TAG, "onResume: Unable to register callback for provisioning changes.");
         }
+
+        IntentFilter intentFilter =
+                new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        registerReceiver(mReceiver, intentFilter);
     }
 
     private void updateVtWfc() {
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 874c412..d451ccf 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -20,6 +20,7 @@
 import static android.service.carrier.CarrierService.ICarrierServiceWrapper.RESULT_ERROR;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -55,7 +56,7 @@
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.SubscriptionInfoUpdater;
 import com.android.internal.telephony.TelephonyPermissions;
-import com.android.internal.util.ArrayUtils;
+import com.android.internal.telephony.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
 
@@ -94,6 +95,8 @@
     private PersistableBundle[] mConfigFromDefaultApp;
     // Carrier configs from privileged carrier config app, indexed by phoneID.
     private PersistableBundle[] mConfigFromCarrierApp;
+    // Persistent Carrier configs that are provided via the override test API, indexed by phone ID.
+    private PersistableBundle[] mPersistentOverrideConfigs;
     // Carrier configs that are provided via the override test API, indexed by phone ID.
     private PersistableBundle[] mOverrideConfigs;
     // Service connection for binding to config app.
@@ -107,7 +110,7 @@
     private final BroadcastReceiver mBootReceiver = new ConfigLoaderBroadcastReceiver();
     // Broadcast receiver for SIM and pkg intents, register intent filter in constructor.
     private final BroadcastReceiver mPackageReceiver = new ConfigLoaderBroadcastReceiver();
-    private final LocalLog mCarrierConfigLoadingLog = new LocalLog(50);
+    private final LocalLog mCarrierConfigLoadingLog = new LocalLog(100);
 
 
     // Message codes; see mHandler below.
@@ -151,6 +154,8 @@
     private static final String TAG_VERSION = "package_version";
     private static final String TAG_BUNDLE = "bundle_data";
 
+    private static final String OVERRIDE_PACKAGE_ADDITION = "-override";
+
     // SharedPreferences key for last known build fingerprint.
     private static final String KEY_FINGERPRINT = "build_fingerprint";
 
@@ -195,6 +200,7 @@
                         // have sent it before unlock. This will avoid we try to load carrier config
                         // when SIM is still loading when unlock happens.
                         if (mHasSentConfigChange[i]) {
+                            logWithLocalLog("System unlocked");
                             updateConfigForPhoneId(i);
                         }
                     }
@@ -209,6 +215,8 @@
                     if (clearCachedConfigForPackage(carrierPackageName)) {
                         int numPhones = TelephonyManager.from(mContext).getActiveModemCount();
                         for (int i = 0; i < numPhones; ++i) {
+                            logWithLocalLog("Package changed: " + carrierPackageName
+                                    + ", phone=" + i);
                             updateConfigForPhoneId(i);
                         }
                     }
@@ -217,8 +225,17 @@
 
                 case EVENT_DO_FETCH_DEFAULT:
                 {
-                    final PersistableBundle config =
-                            restoreConfigFromXml(mPlatformCarrierConfigPackage, phoneId);
+                    // Restore persistent override values.
+                    PersistableBundle config = restoreConfigFromXml(
+                            mPlatformCarrierConfigPackage, OVERRIDE_PACKAGE_ADDITION, phoneId);
+                    if (config != null) {
+                        log("Loaded persistent override config from XML. package="
+                                + mPlatformCarrierConfigPackage
+                                + " phoneId=" + phoneId);
+                        mPersistentOverrideConfigs[phoneId] = config;
+                    }
+
+                    config = restoreConfigFromXml(mPlatformCarrierConfigPackage, "", phoneId);
                     if (config != null) {
                         log(
                                 "Loaded config from XML. package="
@@ -280,7 +297,7 @@
                                     }
                                     PersistableBundle config =
                                             resultData.getParcelable(KEY_CONFIG_BUNDLE);
-                                    saveConfigToXml(mPlatformCarrierConfigPackage, phoneId,
+                                    saveConfigToXml(mPlatformCarrierConfigPackage, "", phoneId,
                                         carrierId, config);
                                     mConfigFromDefaultApp[phoneId] = config;
                                     sendMessage(
@@ -348,7 +365,7 @@
                 {
                     final String carrierPackageName = getCarrierPackageForPhoneId(phoneId);
                     final PersistableBundle config =
-                            restoreConfigFromXml(carrierPackageName, phoneId);
+                            restoreConfigFromXml(carrierPackageName, "", phoneId);
                     if (config != null) {
                         log(
                                 "Loaded config from XML. package="
@@ -411,8 +428,8 @@
                                     }
                                     PersistableBundle config =
                                             resultData.getParcelable(KEY_CONFIG_BUNDLE);
-                                    saveConfigToXml(getCarrierPackageForPhoneId(phoneId), phoneId,
-                                        carrierId, config);
+                                    saveConfigToXml(getCarrierPackageForPhoneId(phoneId), "",
+                                            phoneId, carrierId, config);
                                     mConfigFromCarrierApp[phoneId] = config;
                                     sendMessage(
                                             obtainMessage(
@@ -525,6 +542,7 @@
         int numPhones = TelephonyManager.from(context).getSupportedModemCount();
         mConfigFromDefaultApp = new PersistableBundle[numPhones];
         mConfigFromCarrierApp = new PersistableBundle[numPhones];
+        mPersistentOverrideConfigs = new PersistableBundle[numPhones];
         mOverrideConfigs = new PersistableBundle[numPhones];
         mServiceConnection = new CarrierServiceConnection[numPhones];
         mHasSentConfigChange = new boolean[numPhones];
@@ -734,12 +752,13 @@
      * In case of errors or invalid input, no file will be written.
      *
      * @param packageName the name of the package from which we fetched this bundle.
+     * @param extraString An extra string to be used in the XML file name.
      * @param phoneId the phone ID.
      * @param carrierId contains all carrier-identifying information.
      * @param config the bundle to be written. Null will be treated as an empty bundle.
      */
-    private void saveConfigToXml(String packageName, int phoneId, CarrierIdentifier carrierId,
-        PersistableBundle config) {
+    private void saveConfigToXml(String packageName, @NonNull String extraString, int phoneId,
+            CarrierIdentifier carrierId, PersistableBundle config) {
         if (SubscriptionManager.getSimStateForSlotIndex(phoneId)
                 != TelephonyManager.SIM_STATE_LOADED) {
             loge("Skip save config because SIM records are not loaded.");
@@ -773,7 +792,7 @@
         try {
             outFile = new FileOutputStream(
                     new File(mContext.getFilesDir(),
-                            getFilenameForConfig(packageName, iccid, cid)));
+                            getFilenameForConfig(packageName, extraString, iccid, cid)));
             FastXmlSerializer out = new FastXmlSerializer();
             out.setOutput(outFile, "utf-8");
             out.startDocument("utf-8", true);
@@ -807,11 +826,13 @@
      * current version, then null will be returned.
      *
      * @param packageName the name of the package from which we fetched this bundle.
+     * @param extraString An extra string to be used in the XML file name.
      * @param phoneId the phone ID.
      * @return the bundle from the XML file. Returns null if there is no saved config, the saved
      *         version does not match, or reading config fails.
      */
-    private PersistableBundle restoreConfigFromXml(String packageName, int phoneId) {
+    private PersistableBundle restoreConfigFromXml(String packageName, @NonNull String extraString,
+            int phoneId) {
         final String version = getPackageVersion(packageName);
         if (version == null) {
             loge("Failed to get package version for: " + packageName);
@@ -831,11 +852,12 @@
         }
 
         PersistableBundle restoredBundle = null;
+        File file = null;
         FileInputStream inFile = null;
         try {
-            inFile = new FileInputStream(
-                    new File(mContext.getFilesDir(),
-                            getFilenameForConfig(packageName, iccid, cid)));
+            file = new File(mContext.getFilesDir(),
+                    getFilenameForConfig(packageName, extraString, iccid, cid));
+            inFile = new FileInputStream(file);
             XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
             parser.setInput(inFile, "utf-8");
 
@@ -857,7 +879,9 @@
             inFile.close();
         }
         catch (FileNotFoundException e) {
-            loge(e.toString());
+            // Missing file is normal occurrence that might occur with a new sim or when restoring
+            // an override file during boot and should not be treated as an error.
+            if (file != null) log("File not found: " + file.getPath());
         }
         catch (XmlPullParserException e) {
             loge(e.toString());
@@ -898,13 +922,13 @@
     }
 
     /** Builds a canonical file name for a config file. */
-    private String getFilenameForConfig(@NonNull String packageName, @NonNull String iccid,
-                                        int cid) {
+    private String getFilenameForConfig(@NonNull String packageName, @NonNull String extraString,
+                                        @NonNull String iccid, int cid) {
         // the same carrier should have a single copy of XML file named after carrier id.
         // However, it's still possible that platform doesn't recognize the current sim carrier,
         // we will use iccid + carrierid as the canonical file name. carrierid can also handle the
         // cases SIM OTA resolves to different carrier while iccid remains the same.
-        return "carrierconfig-" + packageName + "-" + iccid + "-" + cid + ".xml";
+        return "carrierconfig-" + packageName + extraString + "-" + iccid + "-" + cid + ".xml";
     }
 
     /** Return the current version code of a package, or null if the name is not found. */
@@ -954,24 +978,32 @@
             PersistableBundle config = mConfigFromDefaultApp[phoneId];
             if (config != null) {
                 retConfig.putAll(config);
-                retConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
+                if (getCarrierPackageForPhoneId(phoneId) == null) {
+                    retConfig.putBoolean(
+                            CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
+                }
             }
             config = mConfigFromCarrierApp[phoneId];
             if (config != null) {
                 retConfig.putAll(config);
                 retConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
             }
+            config = mPersistentOverrideConfigs[phoneId];
+            if (config != null) {
+                retConfig.putAll(config);
+                retConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
+            }
             config = mOverrideConfigs[phoneId];
             if (config != null) {
                 retConfig.putAll(config);
-                retConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
             }
         }
         return retConfig;
     }
 
     @Override
-    public void overrideConfig(int subscriptionId, PersistableBundle overrides) {
+    public void overrideConfig(int subscriptionId, @Nullable PersistableBundle overrides,
+            boolean persistent) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.MODIFY_PHONE_STATE, null);
         //TODO: Also check for SHELL UID to restrict this method to testing only (b/131326259)
@@ -980,18 +1012,38 @@
             log("Ignore invalid phoneId: " + phoneId + " for subId: " + subscriptionId);
             return;
         }
+        overrideConfig(mOverrideConfigs, phoneId, overrides);
 
-        if (overrides == null) {
-            mOverrideConfigs[phoneId] = new PersistableBundle();
-        } else if (mOverrideConfigs[phoneId] == null) {
-            mOverrideConfigs[phoneId] = overrides;
-        } else {
-            mOverrideConfigs[phoneId].putAll(overrides);
+        if (persistent) {
+            overrideConfig(mPersistentOverrideConfigs, phoneId, overrides);
+
+            if (overrides != null) {
+                final CarrierIdentifier carrierId = getCarrierIdentifierForPhoneId(phoneId);
+                saveConfigToXml(mPlatformCarrierConfigPackage, OVERRIDE_PACKAGE_ADDITION, phoneId,
+                        carrierId, mPersistentOverrideConfigs[phoneId]);
+            } else {
+                final String iccid = getIccIdForPhoneId(phoneId);
+                final int cid = getSpecificCarrierIdForPhoneId(phoneId);
+                String fileName = getFilenameForConfig(mPlatformCarrierConfigPackage,
+                        OVERRIDE_PACKAGE_ADDITION, iccid, cid);
+                File fileToDelete = new File(mContext.getFilesDir(), fileName);
+                fileToDelete.delete();
+            }
         }
-
         notifySubscriptionInfoUpdater(phoneId);
     }
 
+    private void overrideConfig(@NonNull PersistableBundle[] currentOverrides, int phoneId,
+            @Nullable PersistableBundle overrides) {
+        if (overrides == null) {
+            currentOverrides[phoneId] = new PersistableBundle();
+        } else if (currentOverrides[phoneId] == null) {
+            currentOverrides[phoneId] = overrides;
+        } else {
+            currentOverrides[phoneId].putAll(overrides);
+        }
+    }
+
     @Override
     public void notifyConfigChangedForSubId(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
@@ -1063,6 +1115,8 @@
             // display ConfigFromCarrierApp
             printConfig(mConfigFromCarrierApp[i], pw, "mConfigFromCarrierApp");
             pw.println("");
+            printConfig(mPersistentOverrideConfigs[i], pw, "mPersistentOverrideConfigs");
+            pw.println("");
             printConfig(mOverrideConfigs[i], pw, "mOverrideConfigs");
         }
 
diff --git a/src/com/android/phone/GsmUmtsCallOptions.java b/src/com/android/phone/GsmUmtsCallOptions.java
index 88cae54..51d1b66 100644
--- a/src/com/android/phone/GsmUmtsCallOptions.java
+++ b/src/com/android/phone/GsmUmtsCallOptions.java
@@ -21,6 +21,7 @@
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceScreen;
+import android.provider.Settings;
 import android.telephony.CarrierConfigManager;
 import android.view.MenuItem;
 
@@ -32,7 +33,7 @@
 
     public static final String CALL_FORWARDING_KEY = "call_forwarding_key";
     public static final String CALL_BARRING_KEY = "call_barring_key";
-    private static final String ADDITIONAL_GSM_SETTINGS_KEY = "additional_gsm_call_settings_key";
+    public static final String ADDITIONAL_GSM_SETTINGS_KEY = "additional_gsm_call_settings_key";
 
     @Override
     protected void onCreate(Bundle icicle) {
@@ -69,12 +70,22 @@
             b = PhoneGlobals.getInstance().getCarrierConfig();
         }
 
+        boolean isAirplaneModeOff = true;
+        if (b != null && b.getBoolean(
+                CarrierConfigManager.KEY_DISABLE_SUPPLEMENTARY_SERVICES_IN_AIRPLANE_MODE_BOOL)) {
+            int airplaneMode = Settings.Global.getInt(
+                    subInfoHelper.getPhone().getContext().getContentResolver(),
+                    Settings.Global.AIRPLANE_MODE_ON, PhoneGlobals.AIRPLANE_OFF);
+            isAirplaneModeOff = PhoneGlobals.AIRPLANE_ON != airplaneMode;
+        }
+
         Preference callForwardingPref = prefScreen.findPreference(CALL_FORWARDING_KEY);
         if (callForwardingPref != null) {
             if (b != null && b.getBoolean(
                     CarrierConfigManager.KEY_CALL_FORWARDING_VISIBILITY_BOOL)) {
                 callForwardingPref.setIntent(
                         subInfoHelper.getIntent(GsmUmtsCallForwardOptions.class));
+                callForwardingPref.setEnabled(isAirplaneModeOff);
             } else {
                 prefScreen.removePreference(callForwardingPref);
             }
@@ -89,6 +100,7 @@
                     CarrierConfigManager.KEY_ADDITIONAL_SETTINGS_CALLER_ID_VISIBILITY_BOOL))) {
                 additionalGsmSettingsPref.setIntent(
                         subInfoHelper.getIntent(GsmUmtsAdditionalCallOptions.class));
+                additionalGsmSettingsPref.setEnabled(isAirplaneModeOff);
             } else {
                 prefScreen.removePreference(additionalGsmSettingsPref);
             }
@@ -98,6 +110,7 @@
         if (callBarringPref != null) {
             if (b != null && b.getBoolean(CarrierConfigManager.KEY_CALL_BARRING_VISIBILITY_BOOL)) {
                 callBarringPref.setIntent(subInfoHelper.getIntent(GsmUmtsCallBarringOptions.class));
+                callBarringPref.setEnabled(isAirplaneModeOff);
             } else {
                 prefScreen.removePreference(callBarringPref);
             }
diff --git a/src/com/android/phone/ImsRcsController.java b/src/com/android/phone/ImsRcsController.java
index d1ff56f..06d2367 100644
--- a/src/com/android/phone/ImsRcsController.java
+++ b/src/com/android/phone/ImsRcsController.java
@@ -18,13 +18,22 @@
 
 import android.content.Context;
 import android.net.Uri;
+import android.os.Binder;
+import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
+import android.telephony.ims.ImsException;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
 import android.telephony.ims.aidl.IImsRcsController;
 import android.telephony.ims.aidl.IRcsUceControllerCallback;
 import android.telephony.ims.feature.RcsFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.util.Log;
 
+import com.android.ims.RcsFeatureManager;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.imsphone.ImsPhone;
+
 import java.util.List;
 
 /**
@@ -60,28 +69,94 @@
         ServiceManager.addService(Context.TELEPHONY_IMS_SERVICE, this);
     }
 
+    /**
+     * Register a capability callback which will provide RCS availability updates for the
+     * subscription specified.
+     *
+     * @param subId the subscription ID
+     * @param callback The ImsCapabilityCallback to be registered.
+     */
     @Override
-    public void registerRcsAvailabilityCallback(IImsCapabilityCallback c) {
+    public void registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback)
+            throws RemoteException {
         enforceReadPrivilegedPermission("registerRcsAvailabilityCallback");
+        final long token = Binder.clearCallingIdentity();
+        try {
+            getRcsFeatureManager(subId).registerRcsAvailabilityCallback(callback);
+        } catch (com.android.ims.ImsException e) {
+            Log.e(TAG, "registerRcsAvailabilityCallback: sudId=" + subId + ", " + e.getMessage());
+            throw new ServiceSpecificException(e.getCode());
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
+    /**
+     * Remove the registered capability callback.
+     *
+     * @param subId the subscription ID
+     * @param callback The ImsCapabilityCallback to be removed.
+     */
     @Override
-    public void unregisterRcsAvailabilityCallback(IImsCapabilityCallback c) {
+    public void unregisterRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback) {
         enforceReadPrivilegedPermission("unregisterRcsAvailabilityCallback");
+        final long token = Binder.clearCallingIdentity();
+        try {
+            getRcsFeatureManager(subId).unregisterRcsAvailabilityCallback(callback);
+        } catch (com.android.ims.ImsException e) {
+            Log.e(TAG, "unregisterRcsAvailabilityCallback: sudId=" + subId + "," + e.getMessage());
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
+    /**
+     * Query for the capability of an IMS RCS service
+     *
+     * @param subId the subscription ID
+     * @param capability the RCS capability to query.
+     * @param radioTech the radio tech that this capability failed for
+     * @return true if the RCS capability is capable for this subscription, false otherwise.
+     */
     @Override
     public boolean isCapable(int subId,
-            @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
+            @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
+            @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
         enforceReadPrivilegedPermission("isCapable");
-        return false;
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return getRcsFeatureManager(subId).isCapable(capability, radioTech);
+        } catch (com.android.ims.ImsException e) {
+            Log.e(TAG, "isCapable: sudId=" + subId
+                    + ", capability=" + capability + ", " + e.getMessage());
+            return false;
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
+    /**
+     * Query the availability of an IMS RCS capability.
+     *
+     * @param subId the subscription ID
+     * @param capability the RCS capability to query.
+     * @return true if the RCS capability is currently available for the associated subscription,
+     * false otherwise.
+     */
     @Override
     public boolean isAvailable(int subId,
             @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
         enforceReadPrivilegedPermission("isAvailable");
-        return false;
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return getRcsFeatureManager(subId).isAvailable(capability);
+        } catch (com.android.ims.ImsException e) {
+            Log.e(TAG, "isAvailable: sudId=" + subId
+                    + ", capability=" + capability + ", " + e.getMessage());
+            return false;
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     @Override
@@ -125,4 +200,30 @@
     private void enforceModifyPermission() {
         mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
     }
+
+    /**
+     * Retrieve RcsFeatureManager instance.
+     *
+     * @param subId the subscription ID
+     * @return The RcsFeatureManager instance
+     * @throws SecurityException if getting Phone or RcsFeatureManager instance failed.
+     */
+    private RcsFeatureManager getRcsFeatureManager(int subId) {
+        Phone phone = PhoneGlobals.getPhone(subId);
+        if (phone == null) {
+            throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION,
+                    "Invalid subscription Id: " + subId);
+        }
+        ImsPhone imsPhone = (ImsPhone) phone.getImsPhone();
+        if (imsPhone == null) {
+            throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+                    "Cannot find ImsPhone instance: " + subId);
+        }
+        RcsFeatureManager rcsFeatureManager = imsPhone.getRcsManager();
+        if (rcsFeatureManager == null) {
+            throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
+                    "Cannot find RcsFeatureManager instance: " + subId);
+        }
+        return rcsFeatureManager;
+    }
 }
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index e30078c..fe55335 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -375,12 +375,11 @@
 
             final Notification notification = builder.build();
             List<UserInfo> users = mUserManager.getUsers(true);
-            for (int i = 0; i < users.size(); i++) {
-                final UserInfo user = users.get(i);
+            for (UserInfo user : users) {
                 final UserHandle userHandle = user.getUserHandle();
                 if (!hasUserRestriction(
                         UserManager.DISALLOW_OUTGOING_CALLS, userHandle)
-                        && !user.isManagedProfile()) {
+                        && !mUserManager.isManagedProfile(userHandle.getIdentifier())) {
                     if (!maybeSendVoicemailNotificationUsingDefaultDialer(phone, vmCount, vmNumber,
                             pendingIntent, isSettingsIntent, userHandle, isRefresh)) {
                         notifyAsUser(
@@ -393,12 +392,11 @@
             }
         } else {
             List<UserInfo> users = mUserManager.getUsers(true /* excludeDying */);
-            for (int i = 0; i < users.size(); i++) {
-                final UserInfo user = users.get(i);
+            for (UserInfo user : users) {
                 final UserHandle userHandle = user.getUserHandle();
                 if (!hasUserRestriction(
                         UserManager.DISALLOW_OUTGOING_CALLS, userHandle)
-                        && !user.isManagedProfile()) {
+                        && !mUserManager.isManagedProfile(userHandle.getIdentifier())) {
                     if (!maybeSendVoicemailNotificationUsingDefaultDialer(phone, 0, null, null,
                             false, userHandle, isRefresh)) {
                         cancelAsUser(
@@ -559,7 +557,7 @@
         } else {
             List<UserInfo> users = mUserManager.getUsers(true);
             for (UserInfo user : users) {
-                if (user.isManagedProfile()) {
+                if (mUserManager.isManagedProfile(user.getUserHandle().getIdentifier())) {
                     continue;
                 }
                 UserHandle userHandle = user.getUserHandle();
@@ -691,7 +689,7 @@
                 .setContentText(contentText)
                 .setOnlyAlertOnce(true)
                 .setOngoing(true)
-                .setChannel(NotificationChannelController.CHANNEL_ID_SIM_HIGH_PRIORITY)
+                .setChannelId(NotificationChannelController.CHANNEL_ID_SIM_HIGH_PRIORITY)
                 .setContentIntent(contentIntent);
         final Notification notification = new Notification.BigTextStyle(builder).bigText(
                 contentText).build();
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 1eb5f50..5d4d9b3 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -577,7 +577,9 @@
 
             if (tm != null && tm.isInEmergencyCall()) {
                 // Switch airplane mode back to off.
-                ConnectivityManager.from(this).setAirplaneMode(false);
+                ConnectivityManager cm =
+                        (ConnectivityManager) context.getSystemService(CONNECTIVITY_SERVICE);
+                cm.setAirplaneMode(false);
                 Toast.makeText(this, R.string.radio_off_during_emergency_call, Toast.LENGTH_LONG)
                         .show();
                 Log.i(LOG_TAG, "Ignoring airplane mode: emergency call. Turning airplane off");
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 552c490..296525d 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -1223,6 +1223,7 @@
                         ((SIMRecords) uiccApp.getIccRecords())
                                 .setForbiddenPlmns(onCompleted, fplmns);
                     }
+                    break;
                 case CMD_ERASE_MODEM_CONFIG:
                     request = (MainThreadRequest) msg.obj;
                     onCompleted = obtainMessage(EVENT_ERASE_MODEM_CONFIG_DONE, request);
@@ -1777,6 +1778,7 @@
     }
 
     public boolean needMobileRadioShutdown() {
+        enforceReadPrivilegedPermission("needMobileRadioShutdown");
         /*
          * If any of the Radios are available, it will need to be
          * shutdown. So return true if any Radio is available.
@@ -2031,7 +2033,15 @@
     }
 
     @Override
-    public String getNetworkCountryIsoForPhone(int phoneId) {
+    public String getNetworkCountryIsoForPhone(int phoneId, String callingPackage) {
+        if (!TextUtils.isEmpty(callingPackage)) {
+            final int subId = mSubscriptionController.getSubIdUsingPhoneId(phoneId);
+            if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
+                    mApp, subId, callingPackage, "getNetworkCountryIsoForPhone")) {
+                return "";
+            }
+        }
+
         // Reporting the correct network country is ambiguous when IWLAN could conflict with
         // registered cell info, so return a NULL country instead.
         final long identity = Binder.clearCallingIdentity();
@@ -4619,7 +4629,9 @@
                 // may happen if the device does not support IMS.
                 return "";
             }
-            return resolver.getImsServiceConfiguration(slotId, isCarrierImsService);
+            // TODO: change API to query RCS separately.
+            return resolver.getImsServiceConfiguration(slotId, isCarrierImsService,
+                    ImsFeature.FEATURE_MMTEL);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -5235,9 +5247,17 @@
 
     @Override
     public List<String> getPackagesWithCarrierPrivilegesForAllPhones() {
+        enforceReadPrivilegedPermission("getPackagesWithCarrierPrivilegesForAllPhones");
+
+        final long identity = Binder.clearCallingIdentity();
+
         List<String> privilegedPackages = new ArrayList<>();
-        for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
-           privilegedPackages.addAll(getPackagesWithCarrierPrivileges(i));
+        try {
+            for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
+                privilegedPackages.addAll(getPackagesWithCarrierPrivileges(i));
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
         }
         return privilegedPackages;
     }
diff --git a/src/com/android/phone/ShortcutViewUtils.java b/src/com/android/phone/ShortcutViewUtils.java
index 47ca5ee..e3c5b64 100644
--- a/src/com/android/phone/ShortcutViewUtils.java
+++ b/src/com/android/phone/ShortcutViewUtils.java
@@ -33,7 +33,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import com.android.internal.util.ArrayUtils;
+import com.android.internal.telephony.util.ArrayUtils;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index ebadf88..0806fd1 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -55,6 +55,9 @@
     private static final String NUMBER_VERIFICATION_SUBCOMMAND = "numverify";
     private static final String EMERGENCY_NUMBER_TEST_MODE = "emergency-number-test-mode";
     private static final String CARRIER_CONFIG_SUBCOMMAND = "cc";
+    private static final String DATA_TEST_MODE = "data";
+    private static final String DATA_ENABLE = "enable";
+    private static final String DATA_DISABLE = "disable";
 
     private static final String IMS_SET_CARRIER_SERVICE = "set-ims-service";
     private static final String IMS_GET_CARRIER_SERVICE = "get-ims-service";
@@ -83,6 +86,11 @@
                 STRING_ARRAY, UNKNOWN
     }
 
+    private class CcOptionParseResult {
+        public int mSubId;
+        public boolean mPersistent;
+    }
+
     // Maps carrier config keys to type. It is possible to infer the type for most carrier config
     // keys by looking at the end of the string which usually tells the type.
     // For instance: "xxxx_string", "xxxx_string_array", etc.
@@ -141,6 +149,8 @@
             case CARRIER_CONFIG_SUBCOMMAND: {
                 return handleCcCommand();
             }
+            case DATA_TEST_MODE:
+                return handleDataTestModeCommand();
             default: {
                 return handleDefaultCommands(cmd);
             }
@@ -157,10 +167,13 @@
         pw.println("    IMS Commands.");
         pw.println("  emergency-number-test-mode");
         pw.println("    Emergency Number Test Mode Commands.");
+        pw.println("  data");
+        pw.println("    Data Test Mode Commands.");
         pw.println("  cc");
         pw.println("    Carrier Config Commands.");
         onHelpIms();
         onHelpEmergencyNumber();
+        onHelpDataTestMode();
         onHelpCc();
     }
 
@@ -202,6 +215,13 @@
         pw.println("    1 if the call would have been intercepted, 0 otherwise.");
     }
 
+    private void onHelpDataTestMode() {
+        PrintWriter pw = getOutPrintWriter();
+        pw.println("Mobile Data Test Mode Commands:");
+        pw.println("  data enable: enable mobile data connectivity");
+        pw.println("  data disable: disable mobile data connectivity");
+    }
+
     private void onHelpEmergencyNumber() {
         PrintWriter pw = getOutPrintWriter();
         pw.println("Emergency Number Test Mode Commands:");
@@ -226,11 +246,12 @@
         pw.println("          is specified, it will choose the default voice SIM slot.");
         pw.println("    KEY: The key to the carrier config value to print. All values are printed");
         pw.println("         if KEY is not specified.");
-        pw.println("  cc set-value [-s SLOT_ID] KEY [NEW_VALUE]");
+        pw.println("  cc set-value [-s SLOT_ID] [-p] KEY [NEW_VALUE]");
         pw.println("    Set carrier config KEY to NEW_VALUE.");
         pw.println("    Options are:");
         pw.println("      -s: The SIM slot ID to set carrier config value for. If no option");
         pw.println("          is specified, it will choose the default voice SIM slot.");
+        pw.println("      -p: Value will be stored persistent");
         pw.println("    NEW_VALUE specifies the new value for carrier config KEY. Null will be");
         pw.println("      used if NEW_VALUE is not set. Strings should be encapsulated with");
         pw.println("      quotation marks. Spaces needs to be escaped. Example: \"Hello\\ World\"");
@@ -271,6 +292,41 @@
         return -1;
     }
 
+    private int handleDataTestModeCommand() {
+        PrintWriter errPw = getErrPrintWriter();
+        String arg = getNextArgRequired();
+        if (arg == null) {
+            onHelpDataTestMode();
+            return 0;
+        }
+        switch (arg) {
+            case DATA_ENABLE: {
+                try {
+                    mInterface.enableDataConnectivity();
+                } catch (RemoteException ex) {
+                    Log.w(LOG_TAG, "data enable, error " + ex.getMessage());
+                    errPw.println("Exception: " + ex.getMessage());
+                    return -1;
+                }
+                break;
+            }
+            case DATA_DISABLE: {
+                try {
+                    mInterface.disableDataConnectivity();
+                } catch (RemoteException ex) {
+                    Log.w(LOG_TAG, "data disable, error " + ex.getMessage());
+                    errPw.println("Exception: " + ex.getMessage());
+                    return -1;
+                }
+                break;
+            }
+            default:
+                onHelpDataTestMode();
+                break;
+        }
+        return 0;
+    }
+
     private int handleEmergencyNumberTestModeCommand() {
         PrintWriter errPw = getErrPrintWriter();
         String opt = getNextOption();
@@ -568,32 +624,47 @@
         return slotId;
     }
 
-    // Get the subId from argument SLOT_ID if it was provided. Otherwise use the default
-    // subscription.
-    private int getSubIdFromArgumentSlotId(String tag) {
+    // Parse options related to Carrier Config Commands.
+    private CcOptionParseResult parseCcOptions(String tag, boolean allowOptionPersistent) {
         PrintWriter errPw = getErrPrintWriter();
-        int subId = SubscriptionManager.getDefaultSubscriptionId();
-        String opt;
+        CcOptionParseResult result = new CcOptionParseResult();
+        result.mSubId = SubscriptionManager.getDefaultSubscriptionId();
+        result.mPersistent = false;
 
+        String opt;
         while ((opt = getNextOption()) != null) {
             switch (opt) {
                 case "-s": {
                     try {
-                        subId = slotStringToSubId(tag, getNextArgRequired());
+                        result.mSubId = slotStringToSubId(tag, getNextArgRequired());
+                        if (!SubscriptionManager.isValidSubscriptionId(result.mSubId)) {
+                            errPw.println(tag + "No valid subscription found.");
+                            return null;
+                        }
+
                     } catch (IllegalArgumentException e) {
                         // Missing slot id
                         errPw.println(tag + "SLOT_ID expected after -s.");
-                        return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+                        return null;
+                    }
+                    break;
+                }
+                case "-p": {
+                    if (allowOptionPersistent) {
+                        result.mPersistent = true;
+                    } else {
+                        errPw.println(tag + "Unexpected option " + opt);
+                        return null;
                     }
                     break;
                 }
                 default: {
                     errPw.println(tag + "Unknown option " + opt);
-                    return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+                    return null;
                 }
             }
         }
-        return subId;
+        return result;
     }
 
     private int slotStringToSubId(String tag, String slotString) {
@@ -657,17 +728,16 @@
         String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_GET_VALUE + ": ";
         String key = null;
 
-        // Get the subId from the SLOT_ID-argument.
-        int subId = getSubIdFromArgumentSlotId(tag);
-        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
-            errPw.println(tag + "No valid subscription found.");
+        // Parse all options
+        CcOptionParseResult options =  parseCcOptions(tag, false);
+        if (options == null) {
             return -1;
         }
 
         // Get bundle containing all carrier configuration values.
-        PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(subId);
+        PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(options.mSubId);
         if (bundle == null) {
-            errPw.println(tag + "No carrier config values found for subId " + subId + ".");
+            errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
             return -1;
         }
 
@@ -698,17 +768,16 @@
         PrintWriter errPw = getErrPrintWriter();
         String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUE + ": ";
 
-        // Get the subId from the SLOT_ID-argument.
-        int subId = getSubIdFromArgumentSlotId(tag);
-        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
-            errPw.println(tag + "No valid subscription found.");
+        // Parse all options
+        CcOptionParseResult options =  parseCcOptions(tag, true);
+        if (options == null) {
             return -1;
         }
 
         // Get bundle containing all current carrier configuration values.
-        PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(subId);
+        PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
         if (originalValues == null) {
-            errPw.println(tag + "No carrier config values found for subId " + subId + ".");
+            errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
             return -1;
         }
 
@@ -745,12 +814,12 @@
         }
 
         // Override the value
-        mCarrierConfigManager.overrideConfig(subId, overrideBundle);
+        mCarrierConfigManager.overrideConfig(options.mSubId, overrideBundle, options.mPersistent);
 
         // Find bundle containing all new carrier configuration values after the override.
-        PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(subId);
+        PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
         if (newValues == null) {
-            errPw.println(tag + "No carrier config values found for subId " + subId + ".");
+            errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
             return -1;
         }
 
@@ -768,15 +837,14 @@
         PrintWriter errPw = getErrPrintWriter();
         String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_CLEAR_VALUES + ": ";
 
-        // Get the subId from the SLOT_ID-argument.
-        int subId = getSubIdFromArgumentSlotId(tag);
-        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
-            errPw.println(tag + "No valid subscription found.");
+        // Parse all options
+        CcOptionParseResult options =  parseCcOptions(tag, false);
+        if (options == null) {
             return -1;
         }
 
         // Clear all values that has previously been set.
-        mCarrierConfigManager.overrideConfig(subId, null);
+        mCarrierConfigManager.overrideConfig(options.mSubId, null, true);
         getOutPrintWriter()
                 .println("All previously set carrier config override values has been cleared");
         return 0;
diff --git a/src/com/android/phone/euicc/EuiccUiDispatcherActivity.java b/src/com/android/phone/euicc/EuiccUiDispatcherActivity.java
index 96f04e1..c47e014 100644
--- a/src/com/android/phone/euicc/EuiccUiDispatcherActivity.java
+++ b/src/com/android/phone/euicc/EuiccUiDispatcherActivity.java
@@ -18,6 +18,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Activity;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -95,7 +96,7 @@
 
         grantDefaultPermissionsToActiveLuiApp(activityInfo);
 
-        euiccUiIntent.setComponent(activityInfo.getComponentName());
+        euiccUiIntent.setComponent(new ComponentName(activityInfo.packageName, activityInfo.name));
         return euiccUiIntent;
     }
 
diff --git a/src/com/android/phone/settings/BandMode.java b/src/com/android/phone/settings/BandMode.java
new file mode 100644
index 0000000..853075a
--- /dev/null
+++ b/src/com/android/phone/settings/BandMode.java
@@ -0,0 +1,255 @@
+/*
+ * 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.settings;
+
+import android.app.Activity;
+import android.content.DialogInterface;
+import android.os.AsyncResult;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.View;
+import android.view.Window;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+import androidx.appcompat.app.AlertDialog;
+
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
+import com.android.phone.R;
+
+/**
+ * Radio Band Mode Selection Class
+ *
+ * It will query baseband about all available band modes and display them
+ * in screen. It will display all six band modes if the query failed.
+ *
+ * After user select one band, it will send the selection to baseband.
+ *
+ * It will alter user the result of select operation and exit, no matter success
+ * or not.
+ *
+ */
+public class BandMode extends Activity {
+    private static final String LOG_TAG = "phone";
+    private static final boolean DBG = false;
+
+    private static final int EVENT_BAND_SCAN_COMPLETED = 100;
+    private static final int EVENT_BAND_SELECTION_DONE = 200;
+
+    //Directly maps to RIL_RadioBandMode from ril.h
+    private static final String[] BAND_NAMES = new String[] {
+            "Automatic",
+            "Europe",
+            "United States",
+            "Japan",
+            "Australia",
+            "Australia 2",
+            "Cellular 800",
+            "PCS",
+            "Class 3 (JTACS)",
+            "Class 4 (Korea-PCS)",
+            "Class 5",
+            "Class 6 (IMT2000)",
+            "Class 7 (700Mhz-Upper)",
+            "Class 8 (1800Mhz-Upper)",
+            "Class 9 (900Mhz)",
+            "Class 10 (800Mhz-Secondary)",
+            "Class 11 (Europe PAMR 400Mhz)",
+            "Class 15 (US-AWS)",
+            "Class 16 (US-2500Mhz)"
+    };
+
+    private ListView mBandList;
+    private ArrayAdapter mBandListAdapter;
+    private BandListItem mTargetBand = null;
+    private DialogInterface mProgressPanel;
+
+    private Phone mPhone = null;
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+        setContentView(R.layout.band_mode);
+
+        mPhone = PhoneFactory.getDefaultPhone();
+
+        mBandList = (ListView) findViewById(R.id.band);
+        mBandListAdapter = new ArrayAdapter<BandListItem>(this,
+                android.R.layout.simple_list_item_1);
+        mBandList.setAdapter(mBandListAdapter);
+        mBandList.setOnItemClickListener(mBandSelectionHandler);
+
+        loadBandList();
+    }
+
+    private AdapterView.OnItemClickListener mBandSelectionHandler =
+            new AdapterView.OnItemClickListener() {
+                public void onItemClick(AdapterView parent, View v,
+                        int position, long id) {
+
+                    getWindow().setFeatureInt(
+                            Window.FEATURE_INDETERMINATE_PROGRESS,
+                            Window.PROGRESS_VISIBILITY_ON);
+
+                    mTargetBand = (BandListItem) parent.getAdapter().getItem(position);
+
+                    if (DBG) log("Select band : " + mTargetBand.toString());
+
+                    Message msg =
+                            mHandler.obtainMessage(EVENT_BAND_SELECTION_DONE);
+                    mPhone.setBandMode(mTargetBand.getBand(), msg);
+                }
+            };
+
+    private static class BandListItem {
+        private int mBandMode = Phone.BM_UNSPECIFIED;
+
+        BandListItem(int bm) {
+            mBandMode = bm;
+        }
+
+        public int getBand() {
+            return mBandMode;
+        }
+
+        public String toString() {
+            if (mBandMode >= BAND_NAMES.length) return "Band mode " + mBandMode;
+            return BAND_NAMES[mBandMode];
+        }
+    }
+
+    private void loadBandList() {
+        String str = getString(R.string.band_mode_loading);
+
+        if (DBG) log(str);
+
+
+        //ProgressDialog.show(this, null, str, true, true, null);
+        mProgressPanel = new AlertDialog.Builder(this)
+            .setMessage(str)
+            .show();
+
+        Message msg = mHandler.obtainMessage(EVENT_BAND_SCAN_COMPLETED);
+        mPhone.queryAvailableBandMode(msg);
+
+    }
+
+    private void bandListLoaded(AsyncResult result) {
+        if (DBG) log("network list loaded");
+
+        if (mProgressPanel != null) mProgressPanel.dismiss();
+
+        clearList();
+
+        boolean addBandSuccess = false;
+        BandListItem item;
+
+        if (result.result != null) {
+            int [] bands = (int []) result.result;
+
+            if (bands.length == 0) {
+                Log.wtf(LOG_TAG, "No Supported Band Modes");
+                return;
+            }
+
+            int size = bands[0];
+
+            if (size > 0) {
+                mBandListAdapter.add(
+                        new BandListItem(Phone.BM_UNSPECIFIED)); //Always include AUTOMATIC
+                for (int i = 1; i <= size; i++) {
+                    if (bands[i] == Phone.BM_UNSPECIFIED) {
+                        continue;
+                    }
+                    item = new BandListItem(bands[i]);
+                    mBandListAdapter.add(item);
+                    if (DBG) log("Add " + item.toString());
+                }
+                addBandSuccess = true;
+            }
+        }
+
+        if (!addBandSuccess) {
+            if (DBG) log("Error in query, add default list");
+            for (int i = 0; i < Phone.BM_NUM_BAND_MODES; i++) {
+                item = new BandListItem(i);
+                mBandListAdapter.add(item);
+                if (DBG) log("Add default " + item.toString());
+            }
+        }
+        mBandList.requestFocus();
+    }
+
+    private void displayBandSelectionResult(Throwable ex) {
+        String status = getString(R.string.band_mode_set)
+                + " [" + mTargetBand.toString() + "] ";
+
+        if (ex != null) {
+            status = status + getString(R.string.band_mode_failed);
+        } else {
+            status = status + getString(R.string.band_mode_succeeded);
+        }
+
+        mProgressPanel = new AlertDialog.Builder(this)
+            .setMessage(status)
+            .setPositiveButton(android.R.string.ok, null).show();
+    }
+
+    private void clearList() {
+        while (mBandListAdapter.getCount() > 0) {
+            mBandListAdapter.remove(
+                    mBandListAdapter.getItem(0));
+        }
+    }
+
+    private void log(String msg) {
+        Log.d(LOG_TAG, "[BandsList] " + msg);
+    }
+
+    private Handler mHandler = new Handler() {
+        public void handleMessage(Message msg) {
+            AsyncResult ar;
+            switch (msg.what) {
+                case EVENT_BAND_SCAN_COMPLETED:
+                    ar = (AsyncResult) msg.obj;
+
+                    bandListLoaded(ar);
+                    break;
+
+                case EVENT_BAND_SELECTION_DONE:
+                    ar = (AsyncResult) msg.obj;
+
+                    getWindow().setFeatureInt(
+                            Window.FEATURE_INDETERMINATE_PROGRESS,
+                            Window.PROGRESS_VISIBILITY_OFF);
+
+                    if (!isFinishing()) {
+                        displayBandSelectionResult(ar.exception);
+                    }
+                    break;
+            }
+        }
+    };
+
+
+}
diff --git a/src/com/android/phone/settings/RadioInfo.java b/src/com/android/phone/settings/RadioInfo.java
new file mode 100644
index 0000000..ce5b839
--- /dev/null
+++ b/src/com/android/phone/settings/RadioInfo.java
@@ -0,0 +1,1772 @@
+/*
+ * 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.settings;
+
+import static android.net.ConnectivityManager.NetworkCallback;
+import static android.provider.Settings.Global.PREFERRED_NETWORK_MODE;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.graphics.Typeface;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.net.TrafficStats;
+import android.net.Uri;
+import android.os.AsyncResult;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemProperties;
+import android.provider.Settings;
+import android.telephony.CarrierConfigManager;
+import android.telephony.CellIdentityCdma;
+import android.telephony.CellIdentityGsm;
+import android.telephony.CellIdentityLte;
+import android.telephony.CellIdentityWcdma;
+import android.telephony.CellInfo;
+import android.telephony.CellInfoCdma;
+import android.telephony.CellInfoGsm;
+import android.telephony.CellInfoLte;
+import android.telephony.CellInfoWcdma;
+import android.telephony.CellLocation;
+import android.telephony.CellSignalStrengthCdma;
+import android.telephony.CellSignalStrengthGsm;
+import android.telephony.CellSignalStrengthLte;
+import android.telephony.CellSignalStrengthWcdma;
+import android.telephony.PhoneStateListener;
+import android.telephony.PhysicalChannelConfig;
+import android.telephony.PreciseCallState;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.telephony.cdma.CdmaCellLocation;
+import android.telephony.gsm.GsmCellLocation;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.EditText;
+import android.widget.Spinner;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AlertDialog.Builder;
+import androidx.appcompat.app.AppCompatActivity;
+
+import com.android.ims.ImsConfig;
+import com.android.ims.ImsException;
+import com.android.ims.ImsManager;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
+import com.android.phone.R;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Radio Information Class
+ *
+ * Allows user to read and alter some of the radio related information.
+ *
+ */
+public class RadioInfo extends AppCompatActivity {
+    private static final String TAG = "RadioInfo";
+
+    private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
+
+    private static final String[] PREFERRED_NETWORK_LABELS = {
+            "WCDMA preferred",
+            "GSM only",
+            "WCDMA only",
+            "GSM auto (PRL)",
+            "CDMA auto (PRL)",
+            "CDMA only",
+            "EvDo only",
+            "Global auto (PRL)",
+            "LTE/CDMA auto (PRL)",
+            "LTE/UMTS auto (PRL)",
+            "LTE/CDMA/UMTS auto (PRL)",
+            "LTE only",
+            "LTE/WCDMA",
+            "TD-SCDMA only",
+            "TD-SCDMA/WCDMA",
+            "LTE/TD-SCDMA",
+            "TD-SCDMA/GSM",
+            "TD-SCDMA/UMTS",
+            "LTE/TD-SCDMA/WCDMA",
+            "LTE/TD-SCDMA/UMTS",
+            "TD-SCDMA/CDMA/UMTS",
+            "Global/TD-SCDMA",
+            "Unknown"
+    };
+
+    private static String[] sPhoneIndexLabels;
+
+    private static final int sCellInfoListRateDisabled = Integer.MAX_VALUE;
+    private static final int sCellInfoListRateMax = 0;
+
+    private static final String OEM_RADIO_INFO_INTENT =
+            "com.android.phone.settings.OEM_RADIO_INFO";
+
+    private static final String DSDS_MODE_PROPERTY = "ro.boot.hardware.dsds";
+
+    /**
+     * A value indicates the device is always on dsds mode.
+     * @see {@link #DSDS_MODE_PROPERTY}
+     */
+    private static final int ALWAYS_ON_DSDS_MODE = 1;
+
+    private static final int IMS_VOLTE_PROVISIONED_CONFIG_ID =
+            ImsConfig.ConfigConstants.VLT_SETTING_ENABLED;
+
+    private static final int IMS_VT_PROVISIONED_CONFIG_ID =
+            ImsConfig.ConfigConstants.LVC_SETTING_ENABLED;
+
+    private static final int IMS_WFC_PROVISIONED_CONFIG_ID =
+            ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED;
+
+    private static final int EAB_PROVISIONED_CONFIG_ID =
+            ImsConfig.ConfigConstants.EAB_SETTING_ENABLED;
+
+    //Values in must match CELL_INFO_REFRESH_RATES
+    private static final String[] CELL_INFO_REFRESH_RATE_LABELS = {
+            "Disabled",
+            "Immediate",
+            "Min 5s",
+            "Min 10s",
+            "Min 60s"
+    };
+
+    //Values in seconds, must match CELL_INFO_REFRESH_RATE_LABELS
+    private static final int [] CELL_INFO_REFRESH_RATES = {
+        sCellInfoListRateDisabled,
+        sCellInfoListRateMax,
+        5000,
+        10000,
+        60000
+    };
+
+    private static void log(String s) {
+        Log.d(TAG, s);
+    }
+
+    private static final int EVENT_CFI_CHANGED = 302;
+
+    private static final int EVENT_QUERY_PREFERRED_TYPE_DONE = 1000;
+    private static final int EVENT_SET_PREFERRED_TYPE_DONE = 1001;
+    private static final int EVENT_QUERY_SMSC_DONE = 1005;
+    private static final int EVENT_UPDATE_SMSC_DONE = 1006;
+    private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 1007;
+
+    private static final int MENU_ITEM_SELECT_BAND         = 0;
+    private static final int MENU_ITEM_VIEW_ADN            = 1;
+    private static final int MENU_ITEM_VIEW_FDN            = 2;
+    private static final int MENU_ITEM_VIEW_SDN            = 3;
+    private static final int MENU_ITEM_GET_IMS_STATUS      = 4;
+    private static final int MENU_ITEM_TOGGLE_DATA         = 5;
+
+    private TextView mDeviceId; //DeviceId is the IMEI in GSM and the MEID in CDMA
+    private TextView mLine1Number;
+    private TextView mSubscriptionId;
+    private TextView mDds;
+    private TextView mSubscriberId;
+    private TextView mCallState;
+    private TextView mOperatorName;
+    private TextView mRoamingState;
+    private TextView mGsmState;
+    private TextView mGprsState;
+    private TextView mVoiceNetwork;
+    private TextView mDataNetwork;
+    private TextView mDBm;
+    private TextView mMwi;
+    private TextView mCfi;
+    private TextView mLocation;
+    private TextView mCellInfo;
+    private TextView mSent;
+    private TextView mReceived;
+    private TextView mPingHostnameV4;
+    private TextView mPingHostnameV6;
+    private TextView mHttpClientTest;
+    private TextView mPhyChanConfig;
+    private TextView mDnsCheckState;
+    private TextView mDownlinkKbps;
+    private TextView mUplinkKbps;
+    private EditText mSmsc;
+    private Switch mRadioPowerOnSwitch;
+    private Button mCellInfoRefreshRateButton;
+    private Button mDnsCheckToggleButton;
+    private Button mPingTestButton;
+    private Button mUpdateSmscButton;
+    private Button mRefreshSmscButton;
+    private Button mOemInfoButton;
+    private Button mCarrierProvisioningButton;
+    private Button mTriggerCarrierProvisioningButton;
+    private Switch mImsVolteProvisionedSwitch;
+    private Switch mImsVtProvisionedSwitch;
+    private Switch mImsWfcProvisionedSwitch;
+    private Switch mEabProvisionedSwitch;
+    private Switch mCbrsDataSwitch;
+    private Switch mDsdsSwitch;
+    private Spinner mPreferredNetworkType;
+    private Spinner mSelectPhoneIndex;
+    private Spinner mCellInfoRefreshRateSpinner;
+
+    private static final long RUNNABLE_TIMEOUT_MS = 5 * 60 * 1000L;
+
+    private ThreadPoolExecutor mQueuedWork;
+
+    private ConnectivityManager mConnectivityManager;
+    private TelephonyManager mTelephonyManager;
+    private ImsManager mImsManager = null;
+    private Phone mPhone = null;
+
+    private String mPingHostnameResultV4;
+    private String mPingHostnameResultV6;
+    private String mHttpClientTestResult;
+    private boolean mMwiValue = false;
+    private boolean mCfiValue = false;
+
+    private List<CellInfo> mCellInfoResult = null;
+    private CellLocation mCellLocationResult = null;
+
+    private int mPreferredNetworkTypeResult;
+    private int mCellInfoRefreshRateIndex;
+    private int mSelectedPhoneIndex;
+
+    private final NetworkRequest mDefaultNetworkRequest = new NetworkRequest.Builder()
+            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+            .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+            .build();
+
+    private final NetworkCallback mNetworkCallback = new NetworkCallback() {
+        public void onCapabilitiesChanged(Network n, NetworkCapabilities nc) {
+            int dlbw = nc.getLinkDownstreamBandwidthKbps();
+            int ulbw = nc.getLinkUpstreamBandwidthKbps();
+            updateBandwidths(dlbw, ulbw);
+        }
+    };
+
+    // not final because we need to recreate this object to register on a new subId (b/117555407)
+    private PhoneStateListener mPhoneStateListener = new RadioInfoPhoneStateListener();
+    private class RadioInfoPhoneStateListener extends PhoneStateListener {
+        @Override
+        public void onDataConnectionStateChanged(int state) {
+            updateDataState();
+            updateNetworkType();
+        }
+
+        @Override
+        public void onDataActivity(int direction) {
+            updateDataStats2();
+        }
+
+        @Override
+        public void onCallStateChanged(int state, String incomingNumber) {
+            updateNetworkType();
+            updatePhoneState(state);
+        }
+
+        @Override
+        public void onPreciseCallStateChanged(PreciseCallState preciseState) {
+            updateNetworkType();
+        }
+
+        @Override
+        public void onCellLocationChanged(CellLocation location) {
+            updateLocation(location);
+        }
+
+        @Override
+        public void onMessageWaitingIndicatorChanged(boolean mwi) {
+            mMwiValue = mwi;
+            updateMessageWaiting();
+        }
+
+        @Override
+        public void onCallForwardingIndicatorChanged(boolean cfi) {
+            mCfiValue = cfi;
+            updateCallRedirect();
+        }
+
+        @Override
+        public void onCellInfoChanged(List<CellInfo> arrayCi) {
+            log("onCellInfoChanged: arrayCi=" + arrayCi);
+            mCellInfoResult = arrayCi;
+            updateCellInfo(mCellInfoResult);
+        }
+
+        @Override
+        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+            log("onSignalStrengthChanged: SignalStrength=" + signalStrength);
+            updateSignalStrength(signalStrength);
+        }
+
+        @Override
+        public void onServiceStateChanged(ServiceState serviceState) {
+            log("onServiceStateChanged: ServiceState=" + serviceState);
+            updateServiceState(serviceState);
+            updateRadioPowerState();
+            updateNetworkType();
+            updateImsProvisionedState();
+        }
+
+    }
+
+    private void updatePhysicalChannelConfiguration(List<PhysicalChannelConfig> configs) {
+        StringBuilder sb = new StringBuilder();
+        String div = "";
+        sb.append("{");
+        if (configs != null) {
+            for (PhysicalChannelConfig c : configs) {
+                sb.append(div).append(c);
+                div = ",";
+            }
+        }
+        sb.append("}");
+        mPhyChanConfig.setText(sb.toString());
+    }
+
+    private void updatePreferredNetworkType(int type) {
+        if (type >= PREFERRED_NETWORK_LABELS.length || type < 0) {
+            log("EVENT_QUERY_PREFERRED_TYPE_DONE: unknown "
+                    + "type=" + type);
+            type = PREFERRED_NETWORK_LABELS.length - 1; //set to Unknown
+        }
+        mPreferredNetworkTypeResult = type;
+
+        mPreferredNetworkType.setSelection(mPreferredNetworkTypeResult, true);
+    }
+
+    private void updatePhoneIndex(int phoneIndex, int subId) {
+        // unregister listeners on the old subId
+        unregisterPhoneStateListener();
+        mTelephonyManager.setCellInfoListRate(sCellInfoListRateDisabled);
+
+        // update the subId
+        mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId);
+
+        // update the phoneId
+        mImsManager = ImsManager.getInstance(getApplicationContext(), phoneIndex);
+        mPhone = PhoneFactory.getPhone(phoneIndex);
+
+        updateAllFields();
+    }
+
+    private Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            AsyncResult ar;
+            switch (msg.what) {
+                case EVENT_QUERY_PREFERRED_TYPE_DONE:
+                    ar = (AsyncResult) msg.obj;
+                    if (ar.exception == null && ar.result != null) {
+                        updatePreferredNetworkType(((int []) ar.result)[0]);
+                    } else {
+                        //In case of an exception, we will set this to unknown
+                        updatePreferredNetworkType(PREFERRED_NETWORK_LABELS.length - 1);
+                    }
+                    break;
+                case EVENT_SET_PREFERRED_TYPE_DONE:
+                    ar = (AsyncResult) msg.obj;
+                    if (ar.exception != null) {
+                        log("Set preferred network type failed.");
+                    }
+                    break;
+                case EVENT_QUERY_SMSC_DONE:
+                    ar = (AsyncResult) msg.obj;
+                    if (ar.exception != null) {
+                        mSmsc.setText("refresh error");
+                    } else {
+                        mSmsc.setText((String) ar.result);
+                    }
+                    break;
+                case EVENT_UPDATE_SMSC_DONE:
+                    mUpdateSmscButton.setEnabled(true);
+                    ar = (AsyncResult) msg.obj;
+                    if (ar.exception != null) {
+                        mSmsc.setText("update error");
+                    }
+                    break;
+                case EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED:
+                    ar = (AsyncResult) msg.obj;
+                    if (ar.exception != null) {
+                        mPhyChanConfig.setText(("update error"));
+                    }
+                    updatePhysicalChannelConfiguration((List<PhysicalChannelConfig>) ar.result);
+                    break;
+                default:
+                    super.handleMessage(msg);
+                    break;
+
+            }
+        }
+    };
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        if (!android.os.Process.myUserHandle().isSystem()) {
+            Log.e(TAG, "Not run from system user, don't do anything.");
+            finish();
+            return;
+        }
+
+        setContentView(R.layout.radio_info);
+
+        log("Started onCreate");
+
+        mQueuedWork = new ThreadPoolExecutor(1, 1, RUNNABLE_TIMEOUT_MS, TimeUnit.MICROSECONDS,
+                new LinkedBlockingDeque<Runnable>());
+        mTelephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
+        mConnectivityManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
+        mPhone = PhoneFactory.getDefaultPhone();
+
+        mImsManager = ImsManager.getInstance(getApplicationContext(),
+                SubscriptionManager.getDefaultVoicePhoneId());
+
+        sPhoneIndexLabels = getPhoneIndexLabels(mTelephonyManager);
+
+        mDeviceId = (TextView) findViewById(R.id.imei);
+        mLine1Number = (TextView) findViewById(R.id.number);
+        mSubscriptionId = (TextView) findViewById(R.id.subid);
+        mDds = (TextView) findViewById(R.id.dds);
+        mSubscriberId = (TextView) findViewById(R.id.imsi);
+        mCallState = (TextView) findViewById(R.id.call);
+        mOperatorName = (TextView) findViewById(R.id.operator);
+        mRoamingState = (TextView) findViewById(R.id.roaming);
+        mGsmState = (TextView) findViewById(R.id.gsm);
+        mGprsState = (TextView) findViewById(R.id.gprs);
+        mVoiceNetwork = (TextView) findViewById(R.id.voice_network);
+        mDataNetwork = (TextView) findViewById(R.id.data_network);
+        mDBm = (TextView) findViewById(R.id.dbm);
+        mMwi = (TextView) findViewById(R.id.mwi);
+        mCfi = (TextView) findViewById(R.id.cfi);
+        mLocation = (TextView) findViewById(R.id.location);
+        mCellInfo = (TextView) findViewById(R.id.cellinfo);
+        mCellInfo.setTypeface(Typeface.MONOSPACE);
+
+        mSent = (TextView) findViewById(R.id.sent);
+        mReceived = (TextView) findViewById(R.id.received);
+        mSmsc = (EditText) findViewById(R.id.smsc);
+        mDnsCheckState = (TextView) findViewById(R.id.dnsCheckState);
+        mPingHostnameV4 = (TextView) findViewById(R.id.pingHostnameV4);
+        mPingHostnameV6 = (TextView) findViewById(R.id.pingHostnameV6);
+        mHttpClientTest = (TextView) findViewById(R.id.httpClientTest);
+
+        mPhyChanConfig = (TextView) findViewById(R.id.phy_chan_config);
+
+        mPreferredNetworkType = (Spinner) findViewById(R.id.preferredNetworkType);
+        ArrayAdapter<String> mPreferredNetworkTypeAdapter = new ArrayAdapter<String>(this,
+                android.R.layout.simple_spinner_item, PREFERRED_NETWORK_LABELS);
+        mPreferredNetworkTypeAdapter
+                .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        mPreferredNetworkType.setAdapter(mPreferredNetworkTypeAdapter);
+
+        mSelectPhoneIndex = (Spinner) findViewById(R.id.phoneIndex);
+        ArrayAdapter<String> phoneIndexAdapter = new ArrayAdapter<String>(this,
+                android.R.layout.simple_spinner_item, sPhoneIndexLabels);
+        phoneIndexAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        mSelectPhoneIndex.setAdapter(phoneIndexAdapter);
+
+        mCellInfoRefreshRateSpinner = (Spinner) findViewById(R.id.cell_info_rate_select);
+        ArrayAdapter<String> cellInfoAdapter = new ArrayAdapter<String>(this,
+                android.R.layout.simple_spinner_item, CELL_INFO_REFRESH_RATE_LABELS);
+        cellInfoAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        mCellInfoRefreshRateSpinner.setAdapter(cellInfoAdapter);
+
+        mImsVolteProvisionedSwitch = (Switch) findViewById(R.id.volte_provisioned_switch);
+        mImsVtProvisionedSwitch = (Switch) findViewById(R.id.vt_provisioned_switch);
+        mImsWfcProvisionedSwitch = (Switch) findViewById(R.id.wfc_provisioned_switch);
+        mEabProvisionedSwitch = (Switch) findViewById(R.id.eab_provisioned_switch);
+
+        if (!ImsManager.isImsSupportedOnDevice(mPhone.getContext())) {
+            mImsVolteProvisionedSwitch.setVisibility(View.GONE);
+            mImsVtProvisionedSwitch.setVisibility(View.GONE);
+            mImsWfcProvisionedSwitch.setVisibility(View.GONE);
+            mEabProvisionedSwitch.setVisibility(View.GONE);
+        }
+
+        mCbrsDataSwitch = (Switch) findViewById(R.id.cbrs_data_switch);
+        mCbrsDataSwitch.setVisibility(isCbrsSupported() ? View.VISIBLE : View.GONE);
+
+        mDsdsSwitch = findViewById(R.id.dsds_switch);
+        if (isDsdsSupported() && !dsdsModeOnly()) {
+            mDsdsSwitch.setVisibility(View.VISIBLE);
+            mDsdsSwitch.setOnClickListener(v -> {
+                if (mTelephonyManager.doesSwitchMultiSimConfigTriggerReboot()) {
+                    // Undo the click action until user clicks the confirm dialog.
+                    mDsdsSwitch.toggle();
+                    showDsdsChangeDialog();
+                } else {
+                    performDsdsSwitch();
+                }
+            });
+            mDsdsSwitch.setChecked(isDsdsEnabled());
+        } else {
+            mDsdsSwitch.setVisibility(View.GONE);
+        }
+
+        mRadioPowerOnSwitch = (Switch) findViewById(R.id.radio_power);
+
+        mDownlinkKbps = (TextView) findViewById(R.id.dl_kbps);
+        mUplinkKbps = (TextView) findViewById(R.id.ul_kbps);
+        updateBandwidths(0, 0);
+
+        mPingTestButton = (Button) findViewById(R.id.ping_test);
+        mPingTestButton.setOnClickListener(mPingButtonHandler);
+        mUpdateSmscButton = (Button) findViewById(R.id.update_smsc);
+        mUpdateSmscButton.setOnClickListener(mUpdateSmscButtonHandler);
+        mRefreshSmscButton = (Button) findViewById(R.id.refresh_smsc);
+        mRefreshSmscButton.setOnClickListener(mRefreshSmscButtonHandler);
+        mDnsCheckToggleButton = (Button) findViewById(R.id.dns_check_toggle);
+        mDnsCheckToggleButton.setOnClickListener(mDnsCheckButtonHandler);
+        mCarrierProvisioningButton = (Button) findViewById(R.id.carrier_provisioning);
+        mCarrierProvisioningButton.setOnClickListener(mCarrierProvisioningButtonHandler);
+        mTriggerCarrierProvisioningButton = (Button) findViewById(
+                R.id.trigger_carrier_provisioning);
+        mTriggerCarrierProvisioningButton.setOnClickListener(
+                mTriggerCarrierProvisioningButtonHandler);
+
+        mOemInfoButton = (Button) findViewById(R.id.oem_info);
+        mOemInfoButton.setOnClickListener(mOemInfoButtonHandler);
+        PackageManager pm = getPackageManager();
+        Intent oemInfoIntent = new Intent(OEM_RADIO_INFO_INTENT);
+        List<ResolveInfo> oemInfoIntentList = pm.queryIntentActivities(oemInfoIntent, 0);
+        if (oemInfoIntentList.size() == 0) {
+            mOemInfoButton.setEnabled(false);
+        }
+
+        mCellInfoRefreshRateIndex = 0; //disabled
+        mPreferredNetworkTypeResult = PREFERRED_NETWORK_LABELS.length - 1; //Unknown
+        mSelectedPhoneIndex = 0; //phone 0
+
+        //FIXME: Replace with TelephonyManager call
+        mPhone.getPreferredNetworkType(
+                mHandler.obtainMessage(EVENT_QUERY_PREFERRED_TYPE_DONE));
+
+        restoreFromBundle(icicle);
+    }
+
+    @Override
+    public Intent getParentActivityIntent() {
+        Intent parentActivity = super.getParentActivityIntent();
+        if (parentActivity == null) {
+            parentActivity = (new Intent()).setClassName("com.android.settings",
+                    "com.android.settings.Settings$TestingSettingsActivity");
+        }
+        return parentActivity;
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        log("Started onResume");
+
+        updateAllFields();
+    }
+
+    private void updateAllFields() {
+        updateMessageWaiting();
+        updateCallRedirect();
+        updateDataState();
+        updateDataStats2();
+        updateRadioPowerState();
+        updateImsProvisionedState();
+        updateProperties();
+        updateDnsCheckState();
+        updateNetworkType();
+
+        updateLocation(mCellLocationResult);
+        updateCellInfo(mCellInfoResult);
+        updateSubscriptionIds();
+
+        mPingHostnameV4.setText(mPingHostnameResultV4);
+        mPingHostnameV6.setText(mPingHostnameResultV6);
+        mHttpClientTest.setText(mHttpClientTestResult);
+
+        mCellInfoRefreshRateSpinner.setOnItemSelectedListener(mCellInfoRefreshRateHandler);
+        //set selection after registering listener to force update
+        mCellInfoRefreshRateSpinner.setSelection(mCellInfoRefreshRateIndex);
+
+        //set selection before registering to prevent update
+        mPreferredNetworkType.setSelection(mPreferredNetworkTypeResult, true);
+        mPreferredNetworkType.setOnItemSelectedListener(mPreferredNetworkHandler);
+
+        // set phone index
+        mSelectPhoneIndex.setSelection(mSelectedPhoneIndex, true);
+        mSelectPhoneIndex.setOnItemSelectedListener(mSelectPhoneIndexHandler);
+
+        mRadioPowerOnSwitch.setOnCheckedChangeListener(mRadioPowerOnChangeListener);
+        mImsVolteProvisionedSwitch.setOnCheckedChangeListener(mImsVolteCheckedChangeListener);
+        mImsVtProvisionedSwitch.setOnCheckedChangeListener(mImsVtCheckedChangeListener);
+        mImsWfcProvisionedSwitch.setOnCheckedChangeListener(mImsWfcCheckedChangeListener);
+        mEabProvisionedSwitch.setOnCheckedChangeListener(mEabCheckedChangeListener);
+
+        if (isCbrsSupported()) {
+            mCbrsDataSwitch.setChecked(getCbrsDataState());
+            mCbrsDataSwitch.setOnCheckedChangeListener(mCbrsDataSwitchChangeListener);
+        }
+
+        unregisterPhoneStateListener();
+        registerPhoneStateListener();
+        mPhone.registerForPhysicalChannelConfig(mHandler,
+            EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED, null);
+
+        mConnectivityManager.registerNetworkCallback(
+                mDefaultNetworkRequest, mNetworkCallback, mHandler);
+
+        mSmsc.clearFocus();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+
+        log("onPause: unregister phone & data intents");
+
+        mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+        mTelephonyManager.setCellInfoListRate(sCellInfoListRateDisabled);
+        mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
+
+    }
+
+    private void restoreFromBundle(Bundle b) {
+        if (b == null) {
+            return;
+        }
+
+        mPingHostnameResultV4 = b.getString("mPingHostnameResultV4", "");
+        mPingHostnameResultV6 = b.getString("mPingHostnameResultV6", "");
+        mHttpClientTestResult = b.getString("mHttpClientTestResult", "");
+
+        mPingHostnameV4.setText(mPingHostnameResultV4);
+        mPingHostnameV6.setText(mPingHostnameResultV6);
+        mHttpClientTest.setText(mHttpClientTestResult);
+
+        mPreferredNetworkTypeResult = b.getInt("mPreferredNetworkTypeResult",
+                PREFERRED_NETWORK_LABELS.length - 1);
+
+        mSelectedPhoneIndex = b.getInt("mSelectedPhoneIndex", 0);
+
+        mCellInfoRefreshRateIndex = b.getInt("mCellInfoRefreshRateIndex", 0);
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        outState.putString("mPingHostnameResultV4", mPingHostnameResultV4);
+        outState.putString("mPingHostnameResultV6", mPingHostnameResultV6);
+        outState.putString("mHttpClientTestResult", mHttpClientTestResult);
+
+        outState.putInt("mPreferredNetworkTypeResult", mPreferredNetworkTypeResult);
+        outState.putInt("mSelectedPhoneIndex", mSelectedPhoneIndex);
+        outState.putInt("mCellInfoRefreshRateIndex", mCellInfoRefreshRateIndex);
+
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        menu.add(0, MENU_ITEM_SELECT_BAND, 0, R.string.radio_info_band_mode_label)
+                .setOnMenuItemClickListener(mSelectBandCallback)
+                .setAlphabeticShortcut('b');
+        menu.add(1, MENU_ITEM_VIEW_ADN, 0,
+                R.string.radioInfo_menu_viewADN).setOnMenuItemClickListener(mViewADNCallback);
+        menu.add(1, MENU_ITEM_VIEW_FDN, 0,
+                R.string.radioInfo_menu_viewFDN).setOnMenuItemClickListener(mViewFDNCallback);
+        menu.add(1, MENU_ITEM_VIEW_SDN, 0,
+                R.string.radioInfo_menu_viewSDN).setOnMenuItemClickListener(mViewSDNCallback);
+        if (ImsManager.isImsSupportedOnDevice(mPhone.getContext())) {
+            menu.add(1, MENU_ITEM_GET_IMS_STATUS,
+                    0, R.string.radioInfo_menu_getIMS).setOnMenuItemClickListener(mGetImsStatus);
+        }
+        menu.add(1, MENU_ITEM_TOGGLE_DATA,
+                0, R.string.radio_info_data_connection_disable)
+                .setOnMenuItemClickListener(mToggleData);
+        return true;
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        // Get the TOGGLE DATA menu item in the right state.
+        MenuItem item = menu.findItem(MENU_ITEM_TOGGLE_DATA);
+        int state = mTelephonyManager.getDataState();
+        boolean visible = true;
+
+        switch (state) {
+            case TelephonyManager.DATA_CONNECTED:
+            case TelephonyManager.DATA_SUSPENDED:
+                item.setTitle(R.string.radio_info_data_connection_disable);
+                break;
+            case TelephonyManager.DATA_DISCONNECTED:
+                item.setTitle(R.string.radio_info_data_connection_enable);
+                break;
+            default:
+                visible = false;
+                break;
+        }
+        item.setVisible(visible);
+        return true;
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mQueuedWork.shutdown();
+    }
+
+    // returns array of string labels for each phone index. The array index is equal to the phone
+    // index.
+    private static String[] getPhoneIndexLabels(TelephonyManager tm) {
+        int phones = tm.getPhoneCount();
+        String[] labels = new String[phones];
+        for (int i = 0; i < phones; i++) {
+            labels[i] = "Phone " + i;
+        }
+        return labels;
+    }
+
+    private void unregisterPhoneStateListener() {
+        mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+        mPhone.unregisterForPhysicalChannelConfig(mHandler);
+
+        // clear all fields so they are blank until the next listener event occurs
+        mOperatorName.setText("");
+        mGprsState.setText("");
+        mDataNetwork.setText("");
+        mVoiceNetwork.setText("");
+        mSent.setText("");
+        mReceived.setText("");
+        mCallState.setText("");
+        mLocation.setText("");
+        mMwiValue = false;
+        mMwi.setText("");
+        mCfiValue = false;
+        mCfi.setText("");
+        mCellInfo.setText("");
+        mDBm.setText("");
+        mGsmState.setText("");
+        mRoamingState.setText("");
+        mPhyChanConfig.setText("");
+    }
+
+    // register mPhoneStateListener for relevant fields using the current TelephonyManager
+    private void registerPhoneStateListener() {
+        mPhoneStateListener = new RadioInfoPhoneStateListener();
+        mTelephonyManager.listen(mPhoneStateListener,
+                  PhoneStateListener.LISTEN_CALL_STATE
+        //b/27803938 - RadioInfo currently cannot read PRECISE_CALL_STATE
+        //      | PhoneStateListener.LISTEN_PRECISE_CALL_STATE
+                | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
+                | PhoneStateListener.LISTEN_DATA_ACTIVITY
+                | PhoneStateListener.LISTEN_CELL_LOCATION
+                | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
+                | PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
+                | PhoneStateListener.LISTEN_CELL_INFO
+                | PhoneStateListener.LISTEN_SERVICE_STATE
+                | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
+    }
+
+    private void updateDnsCheckState() {
+        //FIXME: Replace with a TelephonyManager call
+        mDnsCheckState.setText(mPhone.isDnsCheckDisabled()
+                ? "0.0.0.0 allowed" : "0.0.0.0 not allowed");
+    }
+
+    private void updateBandwidths(int dlbw, int ulbw) {
+        dlbw = (dlbw < 0 || dlbw == Integer.MAX_VALUE) ? -1 : dlbw;
+        ulbw = (ulbw < 0 || ulbw == Integer.MAX_VALUE) ? -1 : ulbw;
+        mDownlinkKbps.setText(String.format("%-5d", dlbw));
+        mUplinkKbps.setText(String.format("%-5d", ulbw));
+    }
+
+
+    private void updateSignalStrength(SignalStrength signalStrength) {
+        Resources r = getResources();
+
+        int signalDbm = signalStrength.getDbm();
+
+        int signalAsu = signalStrength.getAsuLevel();
+
+        if (-1 == signalAsu) signalAsu = 0;
+
+        mDBm.setText(String.valueOf(signalDbm) + " "
+                + r.getString(R.string.radioInfo_display_dbm) + "   "
+                + String.valueOf(signalAsu) + " "
+                + r.getString(R.string.radioInfo_display_asu));
+    }
+
+    private void updateLocation(CellLocation location) {
+        Resources r = getResources();
+        if (location instanceof GsmCellLocation) {
+            GsmCellLocation loc = (GsmCellLocation) location;
+            int lac = loc.getLac();
+            int cid = loc.getCid();
+            mLocation.setText(r.getString(R.string.radioInfo_lac) + " = "
+                    + ((lac == -1) ? "unknown" : Integer.toHexString(lac))
+                    + "   "
+                    + r.getString(R.string.radioInfo_cid) + " = "
+                    + ((cid == -1) ? "unknown" : Integer.toHexString(cid)));
+        } else if (location instanceof CdmaCellLocation) {
+            CdmaCellLocation loc = (CdmaCellLocation) location;
+            int bid = loc.getBaseStationId();
+            int sid = loc.getSystemId();
+            int nid = loc.getNetworkId();
+            int lat = loc.getBaseStationLatitude();
+            int lon = loc.getBaseStationLongitude();
+            mLocation.setText("BID = "
+                    + ((bid == -1) ? "unknown" : Integer.toHexString(bid))
+                    + "   "
+                    + "SID = "
+                    + ((sid == -1) ? "unknown" : Integer.toHexString(sid))
+                    + "   "
+                    + "NID = "
+                    + ((nid == -1) ? "unknown" : Integer.toHexString(nid))
+                    + "\n"
+                    + "LAT = "
+                    + ((lat == -1) ? "unknown" : Integer.toHexString(lat))
+                    + "   "
+                    + "LONG = "
+                    + ((lon == -1) ? "unknown" : Integer.toHexString(lon)));
+        } else {
+            mLocation.setText("unknown");
+        }
+
+
+    }
+
+    private String getCellInfoDisplayString(int i) {
+        return (i != Integer.MAX_VALUE) ? Integer.toString(i) : "";
+    }
+
+    private String getCellInfoDisplayString(long i) {
+        return (i != Long.MAX_VALUE) ? Long.toString(i) : "";
+    }
+
+    private String getConnectionStatusString(CellInfo ci) {
+        String regStr = "";
+        String connStatStr = "";
+        String connector = "";
+
+        if (ci.isRegistered()) {
+            regStr = "R";
+        }
+        switch (ci.getCellConnectionStatus()) {
+            case CellInfo.CONNECTION_PRIMARY_SERVING: connStatStr = "P"; break;
+            case CellInfo.CONNECTION_SECONDARY_SERVING: connStatStr = "S"; break;
+            case CellInfo.CONNECTION_NONE: connStatStr = "N"; break;
+            case CellInfo.CONNECTION_UNKNOWN: /* Field is unsupported */ break;
+            default: break;
+        }
+        if (!TextUtils.isEmpty(regStr) && !TextUtils.isEmpty(connStatStr)) {
+            connector = "+";
+        }
+
+        return regStr + connector + connStatStr;
+    }
+
+    private String buildCdmaInfoString(CellInfoCdma ci) {
+        CellIdentityCdma cidCdma = ci.getCellIdentity();
+        CellSignalStrengthCdma ssCdma = ci.getCellSignalStrength();
+
+        return String.format("%-3.3s %-5.5s %-5.5s %-5.5s %-6.6s %-6.6s %-6.6s %-6.6s %-5.5s",
+                getConnectionStatusString(ci),
+                getCellInfoDisplayString(cidCdma.getSystemId()),
+                getCellInfoDisplayString(cidCdma.getNetworkId()),
+                getCellInfoDisplayString(cidCdma.getBasestationId()),
+                getCellInfoDisplayString(ssCdma.getCdmaDbm()),
+                getCellInfoDisplayString(ssCdma.getCdmaEcio()),
+                getCellInfoDisplayString(ssCdma.getEvdoDbm()),
+                getCellInfoDisplayString(ssCdma.getEvdoEcio()),
+                getCellInfoDisplayString(ssCdma.getEvdoSnr()));
+    }
+
+    private String buildGsmInfoString(CellInfoGsm ci) {
+        CellIdentityGsm cidGsm = ci.getCellIdentity();
+        CellSignalStrengthGsm ssGsm = ci.getCellSignalStrength();
+
+        return String.format("%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-6.6s %-4.4s %-4.4s\n",
+                getConnectionStatusString(ci),
+                getCellInfoDisplayString(cidGsm.getMcc()),
+                getCellInfoDisplayString(cidGsm.getMnc()),
+                getCellInfoDisplayString(cidGsm.getLac()),
+                getCellInfoDisplayString(cidGsm.getCid()),
+                getCellInfoDisplayString(cidGsm.getArfcn()),
+                getCellInfoDisplayString(cidGsm.getBsic()),
+                getCellInfoDisplayString(ssGsm.getDbm()));
+    }
+
+    private String buildLteInfoString(CellInfoLte ci) {
+        CellIdentityLte cidLte = ci.getCellIdentity();
+        CellSignalStrengthLte ssLte = ci.getCellSignalStrength();
+
+        return String.format(
+                "%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-3.3s %-6.6s %-2.2s %-4.4s %-4.4s %-2.2s\n",
+                getConnectionStatusString(ci),
+                getCellInfoDisplayString(cidLte.getMcc()),
+                getCellInfoDisplayString(cidLte.getMnc()),
+                getCellInfoDisplayString(cidLte.getTac()),
+                getCellInfoDisplayString(cidLte.getCi()),
+                getCellInfoDisplayString(cidLte.getPci()),
+                getCellInfoDisplayString(cidLte.getEarfcn()),
+                getCellInfoDisplayString(cidLte.getBandwidth()),
+                getCellInfoDisplayString(ssLte.getDbm()),
+                getCellInfoDisplayString(ssLte.getRsrq()),
+                getCellInfoDisplayString(ssLte.getTimingAdvance()));
+    }
+
+    private String buildWcdmaInfoString(CellInfoWcdma ci) {
+        CellIdentityWcdma cidWcdma = ci.getCellIdentity();
+        CellSignalStrengthWcdma ssWcdma = ci.getCellSignalStrength();
+
+        return String.format("%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-6.6s %-3.3s %-4.4s\n",
+                getConnectionStatusString(ci),
+                getCellInfoDisplayString(cidWcdma.getMcc()),
+                getCellInfoDisplayString(cidWcdma.getMnc()),
+                getCellInfoDisplayString(cidWcdma.getLac()),
+                getCellInfoDisplayString(cidWcdma.getCid()),
+                getCellInfoDisplayString(cidWcdma.getUarfcn()),
+                getCellInfoDisplayString(cidWcdma.getPsc()),
+                getCellInfoDisplayString(ssWcdma.getDbm()));
+    }
+
+    private String buildCellInfoString(List<CellInfo> arrayCi) {
+        String value = new String();
+        StringBuilder cdmaCells = new StringBuilder(),
+                gsmCells = new StringBuilder(),
+                lteCells = new StringBuilder(),
+                wcdmaCells = new StringBuilder();
+
+        if (arrayCi != null) {
+            for (CellInfo ci : arrayCi) {
+
+                if (ci instanceof CellInfoLte) {
+                    lteCells.append(buildLteInfoString((CellInfoLte) ci));
+                } else if (ci instanceof CellInfoWcdma) {
+                    wcdmaCells.append(buildWcdmaInfoString((CellInfoWcdma) ci));
+                } else if (ci instanceof CellInfoGsm) {
+                    gsmCells.append(buildGsmInfoString((CellInfoGsm) ci));
+                } else if (ci instanceof CellInfoCdma) {
+                    cdmaCells.append(buildCdmaInfoString((CellInfoCdma) ci));
+                }
+            }
+            if (lteCells.length() != 0) {
+                value += String.format(
+                        "LTE\n%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-3.3s"
+                                + " %-6.6s %-2.2s %-4.4s %-4.4s %-2.2s\n",
+                        "SRV", "MCC", "MNC", "TAC", "CID", "PCI",
+                        "EARFCN", "BW", "RSRP", "RSRQ", "TA");
+                value += lteCells.toString();
+            }
+            if (wcdmaCells.length() != 0) {
+                value += String.format(
+                        "WCDMA\n%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-6.6s %-3.3s %-4.4s\n",
+                        "SRV", "MCC", "MNC", "LAC", "CID", "UARFCN", "PSC", "RSCP");
+                value += wcdmaCells.toString();
+            }
+            if (gsmCells.length() != 0) {
+                value += String.format(
+                        "GSM\n%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-6.6s %-4.4s %-4.4s\n",
+                        "SRV", "MCC", "MNC", "LAC", "CID", "ARFCN", "BSIC", "RSSI");
+                value += gsmCells.toString();
+            }
+            if (cdmaCells.length() != 0) {
+                value += String.format(
+                        "CDMA/EVDO\n%-3.3s %-5.5s %-5.5s %-5.5s"
+                                + " %-6.6s %-6.6s %-6.6s %-6.6s %-5.5s\n",
+                        "SRV", "SID", "NID", "BSID",
+                        "C-RSSI", "C-ECIO", "E-RSSI", "E-ECIO", "E-SNR");
+                value += cdmaCells.toString();
+            }
+        } else {
+            value = "unknown";
+        }
+
+        return value.toString();
+    }
+
+    private void updateCellInfo(List<CellInfo> arrayCi) {
+        mCellInfo.setText(buildCellInfoString(arrayCi));
+    }
+
+    private void updateSubscriptionIds() {
+        mSubscriptionId.setText(Integer.toString(mPhone.getSubId()));
+        mDds.setText(Integer.toString(SubscriptionManager.getDefaultDataSubscriptionId()));
+    }
+
+    private void updateMessageWaiting() {
+        mMwi.setText(String.valueOf(mMwiValue));
+    }
+
+    private void updateCallRedirect() {
+        mCfi.setText(String.valueOf(mCfiValue));
+    }
+
+
+    private void updateServiceState(ServiceState serviceState) {
+        int state = serviceState.getState();
+        Resources r = getResources();
+        String display = r.getString(R.string.radioInfo_unknown);
+
+        switch (state) {
+            case ServiceState.STATE_IN_SERVICE:
+                display = r.getString(R.string.radioInfo_service_in);
+                break;
+            case ServiceState.STATE_OUT_OF_SERVICE:
+            case ServiceState.STATE_EMERGENCY_ONLY:
+                display = r.getString(R.string.radioInfo_service_emergency);
+                break;
+            case ServiceState.STATE_POWER_OFF:
+                display = r.getString(R.string.radioInfo_service_off);
+                break;
+        }
+
+        mGsmState.setText(display);
+
+        if (serviceState.getRoaming()) {
+            mRoamingState.setText(R.string.radioInfo_roaming_in);
+        } else {
+            mRoamingState.setText(R.string.radioInfo_roaming_not);
+        }
+
+        mOperatorName.setText(serviceState.getOperatorAlphaLong());
+    }
+
+    private void updatePhoneState(int state) {
+        Resources r = getResources();
+        String display = r.getString(R.string.radioInfo_unknown);
+
+        switch (state) {
+            case TelephonyManager.CALL_STATE_IDLE:
+                display = r.getString(R.string.radioInfo_phone_idle);
+                break;
+            case TelephonyManager.CALL_STATE_RINGING:
+                display = r.getString(R.string.radioInfo_phone_ringing);
+                break;
+            case TelephonyManager.CALL_STATE_OFFHOOK:
+                display = r.getString(R.string.radioInfo_phone_offhook);
+                break;
+        }
+
+        mCallState.setText(display);
+    }
+
+    private void updateDataState() {
+        int state = mTelephonyManager.getDataState();
+        Resources r = getResources();
+        String display = r.getString(R.string.radioInfo_unknown);
+
+        switch (state) {
+            case TelephonyManager.DATA_CONNECTED:
+                display = r.getString(R.string.radioInfo_data_connected);
+                break;
+            case TelephonyManager.DATA_CONNECTING:
+                display = r.getString(R.string.radioInfo_data_connecting);
+                break;
+            case TelephonyManager.DATA_DISCONNECTED:
+                display = r.getString(R.string.radioInfo_data_disconnected);
+                break;
+            case TelephonyManager.DATA_SUSPENDED:
+                display = r.getString(R.string.radioInfo_data_suspended);
+                break;
+        }
+
+        mGprsState.setText(display);
+    }
+
+    private void updateNetworkType() {
+        if (mPhone != null) {
+            ServiceState ss = mPhone.getServiceState();
+            mDataNetwork.setText(ServiceState.rilRadioTechnologyToString(
+                    mPhone.getServiceState().getRilDataRadioTechnology()));
+            mVoiceNetwork.setText(ServiceState.rilRadioTechnologyToString(
+                    mPhone.getServiceState().getRilVoiceRadioTechnology()));
+        }
+    }
+
+    private void updateProperties() {
+        String s;
+        Resources r = getResources();
+
+        s = mPhone.getDeviceId();
+        if (s == null) s = r.getString(R.string.radioInfo_unknown);
+        mDeviceId.setText(s);
+
+        s = mPhone.getSubscriberId();
+        if (s == null) s = r.getString(R.string.radioInfo_unknown);
+        mSubscriberId.setText(s);
+
+        //FIXME: Replace with a TelephonyManager call
+        s = mPhone.getLine1Number();
+        if (s == null) s = r.getString(R.string.radioInfo_unknown);
+        mLine1Number.setText(s);
+    }
+
+    private void updateDataStats2() {
+        Resources r = getResources();
+
+        long txPackets = TrafficStats.getMobileTxPackets();
+        long rxPackets = TrafficStats.getMobileRxPackets();
+        long txBytes   = TrafficStats.getMobileTxBytes();
+        long rxBytes   = TrafficStats.getMobileRxBytes();
+
+        String packets = r.getString(R.string.radioInfo_display_packets);
+        String bytes   = r.getString(R.string.radioInfo_display_bytes);
+
+        mSent.setText(txPackets + " " + packets + ", " + txBytes + " " + bytes);
+        mReceived.setText(rxPackets + " " + packets + ", " + rxBytes + " " + bytes);
+    }
+
+    /**
+     *  Ping a host name
+     */
+    private void pingHostname() {
+        try {
+            try {
+                Process p4 = Runtime.getRuntime().exec("ping -c 1 www.google.com");
+                int status4 = p4.waitFor();
+                if (status4 == 0) {
+                    mPingHostnameResultV4 = "Pass";
+                } else {
+                    mPingHostnameResultV4 = String.format("Fail(%d)", status4);
+                }
+            } catch (IOException e) {
+                mPingHostnameResultV4 = "Fail: IOException";
+            }
+            try {
+                Process p6 = Runtime.getRuntime().exec("ping6 -c 1 www.google.com");
+                int status6 = p6.waitFor();
+                if (status6 == 0) {
+                    mPingHostnameResultV6 = "Pass";
+                } else {
+                    mPingHostnameResultV6 = String.format("Fail(%d)", status6);
+                }
+            } catch (IOException e) {
+                mPingHostnameResultV6 = "Fail: IOException";
+            }
+        } catch (InterruptedException e) {
+            mPingHostnameResultV4 = mPingHostnameResultV6 = "Fail: InterruptedException";
+        }
+    }
+
+    /**
+     * This function checks for basic functionality of HTTP Client.
+     */
+    private void httpClientTest() {
+        HttpURLConnection urlConnection = null;
+        try {
+            // TODO: Hardcoded for now, make it UI configurable
+            URL url = new URL("https://www.google.com");
+            urlConnection = (HttpURLConnection) url.openConnection();
+            if (urlConnection.getResponseCode() == 200) {
+                mHttpClientTestResult = "Pass";
+            } else {
+                mHttpClientTestResult = "Fail: Code: " + urlConnection.getResponseMessage();
+            }
+        } catch (IOException e) {
+            mHttpClientTestResult = "Fail: IOException";
+        } finally {
+            if (urlConnection != null) {
+                urlConnection.disconnect();
+            }
+        }
+    }
+
+    private void refreshSmsc() {
+        mQueuedWork.execute(new Runnable() {
+            public void run() {
+                //FIXME: Replace with a TelephonyManager call
+                mPhone.getSmscAddress(mHandler.obtainMessage(EVENT_QUERY_SMSC_DONE));
+            }
+        });
+    }
+
+    private void updateAllCellInfo() {
+
+        mCellInfo.setText("");
+        mLocation.setText("");
+
+        final Runnable updateAllCellInfoResults = new Runnable() {
+            public void run() {
+                updateLocation(mCellLocationResult);
+                updateCellInfo(mCellInfoResult);
+            }
+        };
+
+        mQueuedWork.execute(new Runnable() {
+            @Override
+            public void run() {
+                mCellInfoResult = mTelephonyManager.getAllCellInfo();
+                mCellLocationResult = mTelephonyManager.getCellLocation();
+
+                mHandler.post(updateAllCellInfoResults);
+            }
+        });
+    }
+
+    private void updatePingState() {
+        // Set all to unknown since the threads will take a few secs to update.
+        mPingHostnameResultV4 = getResources().getString(R.string.radioInfo_unknown);
+        mPingHostnameResultV6 = getResources().getString(R.string.radioInfo_unknown);
+        mHttpClientTestResult = getResources().getString(R.string.radioInfo_unknown);
+
+        mPingHostnameV4.setText(mPingHostnameResultV4);
+        mPingHostnameV6.setText(mPingHostnameResultV6);
+        mHttpClientTest.setText(mHttpClientTestResult);
+
+        final Runnable updatePingResults = new Runnable() {
+            public void run() {
+                mPingHostnameV4.setText(mPingHostnameResultV4);
+                mPingHostnameV6.setText(mPingHostnameResultV6);
+                mHttpClientTest.setText(mHttpClientTestResult);
+            }
+        };
+
+        Thread hostname = new Thread() {
+            @Override
+            public void run() {
+                pingHostname();
+                mHandler.post(updatePingResults);
+            }
+        };
+        hostname.start();
+
+        Thread httpClient = new Thread() {
+            @Override
+            public void run() {
+                httpClientTest();
+                mHandler.post(updatePingResults);
+            }
+        };
+        httpClient.start();
+    }
+
+    private MenuItem.OnMenuItemClickListener mViewADNCallback =
+            new MenuItem.OnMenuItemClickListener() {
+        public boolean onMenuItemClick(MenuItem item) {
+            Intent intent = new Intent(Intent.ACTION_VIEW);
+            // XXX We need to specify the component here because if we don't
+            // the activity manager will try to resolve the type by calling
+            // the content provider, which causes it to be loaded in a process
+            // other than the Dialer process, which causes a lot of stuff to
+            // break.
+            intent.setClassName("com.android.phone", "com.android.phone.SimContacts");
+            startActivity(intent);
+            return true;
+        }
+    };
+
+    private MenuItem.OnMenuItemClickListener mViewFDNCallback =
+            new MenuItem.OnMenuItemClickListener() {
+        public boolean onMenuItemClick(MenuItem item) {
+            Intent intent = new Intent(Intent.ACTION_VIEW);
+            // XXX We need to specify the component here because if we don't
+            // the activity manager will try to resolve the type by calling
+            // the content provider, which causes it to be loaded in a process
+            // other than the Dialer process, which causes a lot of stuff to
+            // break.
+            intent.setClassName("com.android.phone", "com.android.phone.settings.fdn.FdnList");
+            startActivity(intent);
+            return true;
+        }
+    };
+
+    private MenuItem.OnMenuItemClickListener mViewSDNCallback =
+            new MenuItem.OnMenuItemClickListener() {
+        public boolean onMenuItemClick(MenuItem item) {
+            Intent intent = new Intent(
+                    Intent.ACTION_VIEW, Uri.parse("content://icc/sdn"));
+            // XXX We need to specify the component here because if we don't
+            // the activity manager will try to resolve the type by calling
+            // the content provider, which causes it to be loaded in a process
+            // other than the Dialer process, which causes a lot of stuff to
+            // break.
+            intent.setClassName("com.android.phone", "com.android.phone.ADNList");
+            startActivity(intent);
+            return true;
+        }
+    };
+
+    private MenuItem.OnMenuItemClickListener mGetImsStatus =
+            new MenuItem.OnMenuItemClickListener() {
+        public boolean onMenuItemClick(MenuItem item) {
+            boolean isImsRegistered = mPhone.isImsRegistered();
+            boolean availableVolte = mPhone.isVolteEnabled();
+            boolean availableWfc = mPhone.isWifiCallingEnabled();
+            boolean availableVt = mPhone.isVideoEnabled();
+            boolean availableUt = mPhone.isUtEnabled();
+
+            final String imsRegString = isImsRegistered
+                    ? getString(R.string.radio_info_ims_reg_status_registered)
+                    : getString(R.string.radio_info_ims_reg_status_not_registered);
+
+            final String available = getString(R.string.radio_info_ims_feature_status_available);
+            final String unavailable = getString(
+                    R.string.radio_info_ims_feature_status_unavailable);
+
+            String imsStatus = getString(R.string.radio_info_ims_reg_status,
+                    imsRegString,
+                    availableVolte ? available : unavailable,
+                    availableWfc ? available : unavailable,
+                    availableVt ? available : unavailable,
+                    availableUt ? available : unavailable);
+
+            AlertDialog imsDialog = new AlertDialog.Builder(RadioInfo.this)
+                    .setMessage(imsStatus)
+                    .setTitle(getString(R.string.radio_info_ims_reg_status_title))
+                    .create();
+
+            imsDialog.show();
+
+            return true;
+        }
+    };
+
+    private MenuItem.OnMenuItemClickListener mSelectBandCallback =
+            new MenuItem.OnMenuItemClickListener() {
+        public boolean onMenuItemClick(MenuItem item) {
+            Intent intent = new Intent();
+            intent.setClass(RadioInfo.this, BandMode.class);
+            startActivity(intent);
+            return true;
+        }
+    };
+
+    private MenuItem.OnMenuItemClickListener mToggleData =
+            new MenuItem.OnMenuItemClickListener() {
+        public boolean onMenuItemClick(MenuItem item) {
+            int state = mTelephonyManager.getDataState();
+            switch (state) {
+                case TelephonyManager.DATA_CONNECTED:
+                    mTelephonyManager.setDataEnabled(false);
+                    break;
+                case TelephonyManager.DATA_DISCONNECTED:
+                    mTelephonyManager.setDataEnabled(true);
+                    break;
+                default:
+                    // do nothing
+                    break;
+            }
+            return true;
+        }
+    };
+
+    private boolean isRadioOn() {
+        //FIXME: Replace with a TelephonyManager call
+        return mPhone.getServiceState().getState() != ServiceState.STATE_POWER_OFF;
+    }
+
+    private void updateRadioPowerState() {
+        //delightful hack to prevent on-checked-changed calls from
+        //actually forcing the radio preference to its transient/current value.
+        mRadioPowerOnSwitch.setOnCheckedChangeListener(null);
+        mRadioPowerOnSwitch.setChecked(isRadioOn());
+        mRadioPowerOnSwitch.setOnCheckedChangeListener(mRadioPowerOnChangeListener);
+    }
+
+    void setImsVolteProvisionedState(boolean state) {
+        Log.d(TAG, "setImsVolteProvisioned state: " + ((state) ? "on" : "off"));
+        setImsConfigProvisionedState(IMS_VOLTE_PROVISIONED_CONFIG_ID, state);
+    }
+
+    void setImsVtProvisionedState(boolean state) {
+        Log.d(TAG, "setImsVtProvisioned() state: " + ((state) ? "on" : "off"));
+        setImsConfigProvisionedState(IMS_VT_PROVISIONED_CONFIG_ID, state);
+    }
+
+    void setImsWfcProvisionedState(boolean state) {
+        Log.d(TAG, "setImsWfcProvisioned() state: " + ((state) ? "on" : "off"));
+        setImsConfigProvisionedState(IMS_WFC_PROVISIONED_CONFIG_ID, state);
+    }
+
+    void setEabProvisionedState(boolean state) {
+        Log.d(TAG, "setEabProvisioned() state: " + ((state) ? "on" : "off"));
+        setImsConfigProvisionedState(EAB_PROVISIONED_CONFIG_ID, state);
+    }
+
+    void setImsConfigProvisionedState(int configItem, boolean state) {
+        if (mPhone != null && mImsManager != null) {
+            mQueuedWork.execute(new Runnable() {
+                public void run() {
+                    try {
+                        mImsManager.getConfigInterface().setProvisionedValue(
+                                configItem, state ? 1 : 0);
+                    } catch (ImsException e) {
+                        Log.e(TAG, "setImsConfigProvisioned() exception:", e);
+                    }
+                }
+            });
+        }
+    }
+
+    OnCheckedChangeListener mRadioPowerOnChangeListener = new OnCheckedChangeListener() {
+        @Override
+        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+            log("toggle radio power: currently " + (isRadioOn() ? "on" : "off"));
+            mPhone.setRadioPower(isChecked);
+        }
+    };
+
+    private boolean isImsVolteProvisioned() {
+        if (mPhone != null && mImsManager != null) {
+            return mImsManager.isVolteEnabledByPlatform(mPhone.getContext())
+                && mImsManager.isVolteProvisionedOnDevice(mPhone.getContext());
+        }
+        return false;
+    }
+
+    OnCheckedChangeListener mImsVolteCheckedChangeListener = new OnCheckedChangeListener() {
+        @Override
+        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+            setImsVolteProvisionedState(isChecked);
+        }
+    };
+
+    private boolean isImsVtProvisioned() {
+        if (mPhone != null && mImsManager != null) {
+            return mImsManager.isVtEnabledByPlatform(mPhone.getContext())
+                && mImsManager.isVtProvisionedOnDevice(mPhone.getContext());
+        }
+        return false;
+    }
+
+    OnCheckedChangeListener mImsVtCheckedChangeListener = new OnCheckedChangeListener() {
+        @Override
+        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+            setImsVtProvisionedState(isChecked);
+        }
+    };
+
+    private boolean isImsWfcProvisioned() {
+        if (mPhone != null && mImsManager != null) {
+            return mImsManager.isWfcEnabledByPlatform(mPhone.getContext())
+                && mImsManager.isWfcProvisionedOnDevice(mPhone.getContext());
+        }
+        return false;
+    }
+
+    OnCheckedChangeListener mImsWfcCheckedChangeListener = new OnCheckedChangeListener() {
+        @Override
+        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+            setImsWfcProvisionedState(isChecked);
+        }
+    };
+
+    private boolean isEabProvisioned() {
+        return isFeatureProvisioned(EAB_PROVISIONED_CONFIG_ID, false);
+    }
+
+    OnCheckedChangeListener mEabCheckedChangeListener = new OnCheckedChangeListener() {
+        @Override
+        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+            setEabProvisionedState(isChecked);
+        }
+    };
+
+    private boolean isFeatureProvisioned(int featureId, boolean defaultValue) {
+        boolean provisioned = defaultValue;
+        if (mImsManager != null) {
+            try {
+                ImsConfig imsConfig = mImsManager.getConfigInterface();
+                if (imsConfig != null) {
+                    provisioned =
+                            (imsConfig.getProvisionedValue(featureId)
+                                    == ImsConfig.FeatureValueConstants.ON);
+                }
+            } catch (ImsException ex) {
+                Log.e(TAG, "isFeatureProvisioned() exception:", ex);
+            }
+        }
+
+        log("isFeatureProvisioned() featureId=" + featureId + " provisioned=" + provisioned);
+        return provisioned;
+    }
+
+    private static boolean isEabEnabledByPlatform(Context context) {
+        if (context != null) {
+            CarrierConfigManager configManager = (CarrierConfigManager)
+                    context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+            if (configManager != null && configManager.getConfig().getBoolean(
+                        CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void updateImsProvisionedState() {
+        if (!ImsManager.isImsSupportedOnDevice(mPhone.getContext())) {
+            return;
+        }
+        log("updateImsProvisionedState isImsVolteProvisioned()=" + isImsVolteProvisioned());
+        //delightful hack to prevent on-checked-changed calls from
+        //actually forcing the ims provisioning to its transient/current value.
+        mImsVolteProvisionedSwitch.setOnCheckedChangeListener(null);
+        mImsVolteProvisionedSwitch.setChecked(isImsVolteProvisioned());
+        mImsVolteProvisionedSwitch.setOnCheckedChangeListener(mImsVolteCheckedChangeListener);
+        mImsVolteProvisionedSwitch.setEnabled(!IS_USER_BUILD
+                && mImsManager.isVolteEnabledByPlatform(mPhone.getContext()));
+
+        mImsVtProvisionedSwitch.setOnCheckedChangeListener(null);
+        mImsVtProvisionedSwitch.setChecked(isImsVtProvisioned());
+        mImsVtProvisionedSwitch.setOnCheckedChangeListener(mImsVtCheckedChangeListener);
+        mImsVtProvisionedSwitch.setEnabled(!IS_USER_BUILD
+                && mImsManager.isVtEnabledByPlatform(mPhone.getContext()));
+
+        mImsWfcProvisionedSwitch.setOnCheckedChangeListener(null);
+        mImsWfcProvisionedSwitch.setChecked(isImsWfcProvisioned());
+        mImsWfcProvisionedSwitch.setOnCheckedChangeListener(mImsWfcCheckedChangeListener);
+        mImsWfcProvisionedSwitch.setEnabled(!IS_USER_BUILD
+                && mImsManager.isWfcEnabledByPlatform(mPhone.getContext()));
+
+        mEabProvisionedSwitch.setOnCheckedChangeListener(null);
+        mEabProvisionedSwitch.setChecked(isEabProvisioned());
+        mEabProvisionedSwitch.setOnCheckedChangeListener(mEabCheckedChangeListener);
+        mEabProvisionedSwitch.setEnabled(!IS_USER_BUILD
+                && isEabEnabledByPlatform(mPhone.getContext()));
+    }
+
+    OnClickListener mDnsCheckButtonHandler = new OnClickListener() {
+        public void onClick(View v) {
+            //FIXME: Replace with a TelephonyManager call
+            mPhone.disableDnsCheck(!mPhone.isDnsCheckDisabled());
+            updateDnsCheckState();
+        }
+    };
+
+    OnClickListener mOemInfoButtonHandler = new OnClickListener() {
+        public void onClick(View v) {
+            Intent intent = new Intent(OEM_RADIO_INFO_INTENT);
+            try {
+                startActivity(intent);
+            } catch (android.content.ActivityNotFoundException ex) {
+                log("OEM-specific Info/Settings Activity Not Found : " + ex);
+                // If the activity does not exist, there are no OEM
+                // settings, and so we can just do nothing...
+            }
+        }
+    };
+
+    OnClickListener mPingButtonHandler = new OnClickListener() {
+        public void onClick(View v) {
+            updatePingState();
+        }
+    };
+
+    OnClickListener mUpdateSmscButtonHandler = new OnClickListener() {
+        public void onClick(View v) {
+            mUpdateSmscButton.setEnabled(false);
+            mQueuedWork.execute(new Runnable() {
+                public void run() {
+                    mPhone.setSmscAddress(mSmsc.getText().toString(),
+                            mHandler.obtainMessage(EVENT_UPDATE_SMSC_DONE));
+                }
+            });
+        }
+    };
+
+    OnClickListener mRefreshSmscButtonHandler = new OnClickListener() {
+        public void onClick(View v) {
+            refreshSmsc();
+        }
+    };
+
+    OnClickListener mCarrierProvisioningButtonHandler = new OnClickListener() {
+        public void onClick(View v) {
+            final Intent intent = new Intent("com.android.settings.CARRIER_PROVISIONING");
+            final ComponentName serviceComponent = ComponentName.unflattenFromString(
+                    "com.android.omadm.service/.DMIntentReceiver");
+            intent.setComponent(serviceComponent);
+            sendBroadcast(intent);
+        }
+    };
+
+    OnClickListener mTriggerCarrierProvisioningButtonHandler = new OnClickListener() {
+        public void onClick(View v) {
+            final Intent intent = new Intent("com.android.settings.TRIGGER_CARRIER_PROVISIONING");
+            final ComponentName serviceComponent = ComponentName.unflattenFromString(
+                    "com.android.omadm.service/.DMIntentReceiver");
+            intent.setComponent(serviceComponent);
+            sendBroadcast(intent);
+        }
+    };
+
+    AdapterView.OnItemSelectedListener mPreferredNetworkHandler =
+            new AdapterView.OnItemSelectedListener() {
+
+        public void onItemSelected(AdapterView parent, View v, int pos, long id) {
+            if (mPreferredNetworkTypeResult != pos && pos >= 0
+                    && pos <= PREFERRED_NETWORK_LABELS.length - 2) {
+                mPreferredNetworkTypeResult = pos;
+
+                // TODO: Possibly migrate this to TelephonyManager.setPreferredNetworkType()
+                // which today still has some issues (mostly that the "set" is conditional
+                // on a successful modem call, which is not what we want). Instead we always
+                // want this setting to be set, so that if the radio hiccups and this setting
+                // is for some reason unsuccessful, future calls to the radio will reflect
+                // the users's preference which is set here.
+                final int subId = mPhone.getSubId();
+                if (SubscriptionManager.isUsableSubIdValue(subId)) {
+                    Settings.Global.putInt(mPhone.getContext().getContentResolver(),
+                            PREFERRED_NETWORK_MODE + subId, mPreferredNetworkTypeResult);
+                }
+                log("Calling setPreferredNetworkType(" + mPreferredNetworkTypeResult + ")");
+                Message msg = mHandler.obtainMessage(EVENT_SET_PREFERRED_TYPE_DONE);
+                mPhone.setPreferredNetworkType(mPreferredNetworkTypeResult, msg);
+            }
+        }
+
+        public void onNothingSelected(AdapterView parent) {
+        }
+    };
+
+    AdapterView.OnItemSelectedListener mSelectPhoneIndexHandler =
+            new AdapterView.OnItemSelectedListener() {
+
+        public void onItemSelected(AdapterView parent, View v, int pos, long id) {
+            if (pos >= 0 && pos <= sPhoneIndexLabels.length - 1) {
+                // the array position is equal to the phone index
+                int phoneIndex = pos;
+                Phone[] phones = PhoneFactory.getPhones();
+                if (phones == null || phones.length <= phoneIndex) {
+                    return;
+                }
+                // getSubId says it takes a slotIndex, but it actually takes a phone index
+                int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+                int[] subIds = SubscriptionManager.getSubId(phoneIndex);
+                if (subIds != null && subIds.length > 0) {
+                    subId = subIds[0];
+                }
+                mSelectedPhoneIndex = phoneIndex;
+
+                updatePhoneIndex(phoneIndex, subId);
+            }
+        }
+
+        public void onNothingSelected(AdapterView parent) {
+        }
+    };
+
+    AdapterView.OnItemSelectedListener mCellInfoRefreshRateHandler  =
+            new AdapterView.OnItemSelectedListener() {
+
+        public void onItemSelected(AdapterView parent, View v, int pos, long id) {
+            mCellInfoRefreshRateIndex = pos;
+            mTelephonyManager.setCellInfoListRate(CELL_INFO_REFRESH_RATES[pos]);
+            updateAllCellInfo();
+        }
+
+        public void onNothingSelected(AdapterView parent) {
+        }
+    };
+
+    boolean isCbrsSupported() {
+        return getResources().getBoolean(
+              com.android.internal.R.bool.config_cbrs_supported);
+    }
+
+    void updateCbrsDataState(boolean state) {
+        Log.d(TAG, "setCbrsDataSwitchState() state:" + ((state) ? "on" : "off"));
+        if (mTelephonyManager != null) {
+            mQueuedWork.execute(new Runnable() {
+                public void run() {
+                    mTelephonyManager.setOpportunisticNetworkState(state);
+                    mCbrsDataSwitch.setChecked(getCbrsDataState());
+                }
+            });
+        }
+    }
+
+    boolean getCbrsDataState() {
+        boolean state = false;
+        if (mTelephonyManager != null) {
+            state = mTelephonyManager.isOpportunisticNetworkEnabled();
+        }
+        Log.d(TAG, "getCbrsDataState() state:" + ((state) ? "on" : "off"));
+        return state;
+    }
+
+    OnCheckedChangeListener mCbrsDataSwitchChangeListener = new OnCheckedChangeListener() {
+        @Override
+        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+            updateCbrsDataState(isChecked);
+        }
+    };
+
+    private void showDsdsChangeDialog() {
+        final AlertDialog confirmDialog = new Builder(RadioInfo.this)
+                .setTitle(R.string.dsds_dialog_title)
+                .setMessage(R.string.dsds_dialog_message)
+                .setPositiveButton(R.string.dsds_dialog_confirm, mOnDsdsDialogConfirmedListener)
+                .setNegativeButton(R.string.dsds_dialog_cancel, mOnDsdsDialogConfirmedListener)
+                .create();
+        confirmDialog.show();
+    }
+
+    private static boolean isDsdsSupported() {
+        return (TelephonyManager.getDefault().isMultiSimSupported()
+            == TelephonyManager.MULTISIM_ALLOWED);
+    }
+
+    private static boolean isDsdsEnabled() {
+        return TelephonyManager.getDefault().getPhoneCount() > 1;
+    }
+
+    private void performDsdsSwitch() {
+        mTelephonyManager.switchMultiSimConfig(mDsdsSwitch.isChecked() ? 2 : 1);
+    }
+
+    /**
+     * @return {@code True} if the device is only supported dsds mode.
+     */
+    private boolean dsdsModeOnly() {
+        String dsdsMode = SystemProperties.get(DSDS_MODE_PROPERTY);
+        return !TextUtils.isEmpty(dsdsMode) && Integer.parseInt(dsdsMode) == ALWAYS_ON_DSDS_MODE;
+    }
+
+    DialogInterface.OnClickListener mOnDsdsDialogConfirmedListener =
+            new DialogInterface.OnClickListener() {
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+            if (which == DialogInterface.BUTTON_POSITIVE) {
+                mDsdsSwitch.toggle();
+                performDsdsSwitch();
+            }
+        }
+    };
+}
diff --git a/src/com/android/phone/vvm/RemoteVvmTaskManager.java b/src/com/android/phone/vvm/RemoteVvmTaskManager.java
index 14030a1..6b60303 100644
--- a/src/com/android/phone/vvm/RemoteVvmTaskManager.java
+++ b/src/com/android/phone/vvm/RemoteVvmTaskManager.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.content.pm.ComponentInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Bundle;
@@ -38,6 +39,7 @@
 import android.telephony.VisualVoicemailSms;
 import android.text.TextUtils;
 
+import com.android.internal.telephony.util.TelephonyUtils;
 import com.android.phone.Assert;
 import com.android.phone.R;
 
@@ -167,7 +169,8 @@
             }
             if (info.serviceInfo == null) {
                 VvmLog.w(TAG,
-                        "Component " + info.getComponentInfo() + " is not a service, ignoring");
+                        "Component " + TelephonyUtils.getComponentInfo(info)
+                            + " is not a service, ignoring");
                 continue;
             }
             if (!android.Manifest.permission.BIND_VISUAL_VOICEMAIL_SERVICE
@@ -180,7 +183,8 @@
                 VvmLog.w(TAG, "target package " + targetPackage
                         + " is no longer the active VisualVoicemailService, ignoring");
             }
-            return info.getComponentInfo().getComponentName();
+            ComponentInfo componentInfo = TelephonyUtils.getComponentInfo(info);
+            return new ComponentName(componentInfo.packageName, componentInfo.name);
 
         }
         return null;
@@ -199,7 +203,8 @@
         if (info.isEmpty()) {
             return null;
         }
-        return info.get(0).getComponentInfo().getComponentName();
+        ComponentInfo componentInfo = TelephonyUtils.getComponentInfo(info.get(0));
+        return new ComponentName(componentInfo.packageName, componentInfo.name);
     }
 
     @Override
diff --git a/src/com/android/services/telephony/DeviceState.java b/src/com/android/services/telephony/DeviceState.java
new file mode 100644
index 0000000..7cd2d7e
--- /dev/null
+++ b/src/com/android/services/telephony/DeviceState.java
@@ -0,0 +1,60 @@
+/*
+ * 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.services.telephony;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.telecom.TelecomManager;
+
+import com.android.internal.telephony.PhoneConstants;
+import com.android.phone.R;
+
+/**
+ * Abstracts device state and settings for better testability.
+ */
+public class DeviceState {
+
+    public boolean shouldCheckSimStateBeforeOutgoingCall(Context context) {
+        return context.getResources().getBoolean(
+                R.bool.config_checkSimStateBeforeOutgoingCall);
+    }
+
+    public boolean isSuplDdsSwitchRequiredForEmergencyCall(Context context) {
+        return context.getResources().getBoolean(
+                R.bool.config_gnss_supl_requires_default_data_for_emergency);
+    }
+
+    public boolean isRadioPowerDownAllowedOnBluetooth(Context context) {
+        return context.getResources().getBoolean(R.bool.config_allowRadioPowerDownOnBluetooth);
+    }
+
+    public boolean isAirplaneModeOn(Context context) {
+        return Settings.Global.getInt(context.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON, 0) > 0;
+    }
+
+    public int getCellOnStatus(Context context) {
+        return Settings.Global.getInt(context.getContentResolver(), Settings.Global.CELL_ON,
+                PhoneConstants.CELL_ON_FLAG);
+    }
+
+    public boolean isTtyModeEnabled(Context context) {
+        return android.provider.Settings.Secure.getInt(context.getContentResolver(),
+                android.provider.Settings.Secure.PREFERRED_TTY_MODE,
+                TelecomManager.TTY_MODE_OFF) != TelecomManager.TTY_MODE_OFF;
+    }
+}
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index b47adb2..4c3f9c9 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -1030,9 +1030,9 @@
                 // call log.
                 connection.setDisconnected(new DisconnectCause(DisconnectCause.CANCELED));
                 connection.destroy();
-                handleConnectionDestruction(connection);
             }
             mConferenceParticipantConnections.clear();
+            updateManageConference();
         }
     }
 
diff --git a/src/com/android/services/telephony/PstnIncomingCallNotifier.java b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
index f397dce..2dfeaed 100644
--- a/src/com/android/services/telephony/PstnIncomingCallNotifier.java
+++ b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
@@ -41,8 +41,6 @@
 import com.android.phone.NumberVerificationManager;
 import com.android.phone.PhoneUtils;
 
-import com.google.common.base.Preconditions;
-
 import java.util.Objects;
 
 /**
@@ -96,7 +94,9 @@
      * @param phone The phone object for listening to incoming calls.
      */
     PstnIncomingCallNotifier(Phone phone) {
-        Preconditions.checkNotNull(phone);
+        if (phone == null) {
+            throw new NullPointerException();
+        }
 
         mPhone = phone;
 
diff --git a/src/com/android/services/telephony/PstnPhoneCapabilitiesNotifier.java b/src/com/android/services/telephony/PstnPhoneCapabilitiesNotifier.java
index b9cbf6e..4038dd1 100644
--- a/src/com/android/services/telephony/PstnPhoneCapabilitiesNotifier.java
+++ b/src/com/android/services/telephony/PstnPhoneCapabilitiesNotifier.java
@@ -21,7 +21,6 @@
 import android.os.Message;
 
 import com.android.internal.telephony.Phone;
-import com.android.internal.util.Preconditions;
 
 /**
  * Listens to phone's capabilities changed event and notifies Telecomm. One instance of these exists
@@ -55,7 +54,9 @@
 
     /*package*/
     PstnPhoneCapabilitiesNotifier(Phone phone, Listener listener) {
-        Preconditions.checkNotNull(phone);
+        if (phone == null) {
+            throw new NullPointerException();
+        }
 
         mPhone = phone;
         mListener = listener;
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 092e08b..5a1e6a6 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -35,7 +35,6 @@
 import android.os.Looper;
 import android.os.PersistableBundle;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.provider.Settings;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
@@ -806,10 +805,7 @@
 
                 int userHandleId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                 UserHandle currentUserHandle = UserHandle.of(userHandleId);
-                UserManager userManager =
-                        (UserManager) context.getSystemService(Context.USER_SERVICE);
-                mIsPrimaryUser = userManager.getPrimaryUser().getUserHandle()
-                        .equals(currentUserHandle);
+                mIsPrimaryUser = currentUserHandle.isSystem();
 
                 // Any time the user changes, re-register the accounts.
                 tearDownAccounts();
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index b983667..fb865b4 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -52,6 +52,7 @@
 
 import com.android.ims.ImsCall;
 import com.android.ims.internal.ConferenceParticipant;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallFailCause;
@@ -409,14 +410,26 @@
             }
         }
         if (messageId != -1 && getPhone() != null && getPhone().getContext() != null) {
-            Resources res = SubscriptionManager.getResourcesForSubId(
-                    getPhone().getContext(), getPhone().getSubId());
-            return res.getText(messageId);
+            return getResourceText(messageId);
         } else {
             return null;
         }
     }
 
+    @VisibleForTesting
+    public CharSequence getResourceText(int id) {
+        Resources resources = SubscriptionManager.getResourcesForSubId(getPhone().getContext(),
+                getPhone().getSubId());
+        return resources.getText(id);
+    }
+
+    @VisibleForTesting
+    public String getResourceString(int id) {
+        Resources resources = SubscriptionManager.getResourcesForSubId(getPhone().getContext(),
+                getPhone().getSubId());
+        return resources.getString(id);
+    }
+
     /**
      * @return {@code true} if carrier video conferencing is supported, {@code false} otherwise.
      */
@@ -1507,7 +1520,8 @@
                 || !VideoProfile.isVideo(getVideoState()));
     }
 
-    private PersistableBundle getCarrierConfig() {
+    @VisibleForTesting
+    public PersistableBundle getCarrierConfig() {
         Phone phone = getPhone();
         if (phone == null) {
             return null;
@@ -2294,10 +2308,8 @@
                     : R.string.status_hint_label_wifi_call;
 
             Context context = getPhone().getContext();
-            Resources res =
-                    SubscriptionManager.getResourcesForSubId(context, getPhone().getSubId());
             setTelephonyStatusHints(new StatusHints(
-                    res.getString(labelId),
+                    getResourceString(labelId),
                     Icon.createWithResource(
                             context, R.drawable.ic_signal_wifi_4_bar_24dp),
                     null /* extras */));
@@ -2380,7 +2392,8 @@
      * 3. If call is a video call, carrier supports video conference calls.
      * 4. If call is a wifi call and VoWIFI is disabled and carrier supports merging these calls.
      */
-    private void refreshConferenceSupported() {
+    @VisibleForTesting
+    void refreshConferenceSupported() {
         boolean isVideoCall = VideoProfile.isVideo(getVideoState());
         Phone phone = getPhone();
         if (phone == null) {
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index e6a1fd6..40b941e 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -28,7 +28,6 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
-import android.provider.Settings;
 import android.telecom.Conference;
 import android.telecom.Connection;
 import android.telecom.ConnectionRequest;
@@ -148,12 +147,7 @@
             new TelephonyConferenceController(mTelephonyConnectionServiceProxy);
     private final CdmaConferenceController mCdmaConferenceController =
             new CdmaConferenceController(this);
-    private final ImsConferenceController mImsConferenceController =
-            new ImsConferenceController(TelecomAccountRegistry.getInstance(this),
-                    mTelephonyConnectionServiceProxy,
-                    // FeatureFlagProxy; used to determine if standalone call emulation is enabled.
-                    // TODO: Move to carrier config
-                    () -> true);
+    private ImsConferenceController mImsConferenceController;
 
     private ComponentName mExpectedComponentName = null;
     private RadioOnHelper mRadioOnHelper;
@@ -170,6 +164,7 @@
     public Pair<WeakReference<TelephonyConnection>, Queue<Phone>> mEmergencyRetryCache;
     private Handler mDdsSwitchHandler;
     private HandlerThread mHandlerThread;
+    private DeviceState mDeviceState = new DeviceState();
 
     /**
      * Keeps track of the status of a SIM slot.
@@ -191,7 +186,10 @@
         }
     }
 
-    // SubscriptionManager Proxy interface for testing
+    /**
+     * SubscriptionManager dependencies for testing.
+     */
+    @VisibleForTesting
     public interface SubscriptionManagerProxy {
         int getDefaultVoicePhoneId();
         int getSimStateForSlotIdx(int slotId);
@@ -215,7 +213,9 @@
         }
     };
 
-    // TelephonyManager Proxy interface for testing
+    /**
+     * TelephonyManager dependencies for testing.
+     */
     @VisibleForTesting
     public interface TelephonyManagerProxy {
         int getPhoneCount();
@@ -255,7 +255,9 @@
         }
     }
 
-    //PhoneFactory proxy interface for testing
+    /**
+     * PhoneFactory Dependencies for testing.
+     */
     @VisibleForTesting
     public interface PhoneFactoryProxy {
         Phone getPhone(int index);
@@ -280,22 +282,185 @@
         }
     };
 
+    /**
+     * PhoneUtils dependencies for testing.
+     */
+    @VisibleForTesting
+    public interface PhoneUtilsProxy {
+        int getSubIdForPhoneAccountHandle(PhoneAccountHandle accountHandle);
+        PhoneAccountHandle makePstnPhoneAccountHandle(Phone phone);
+        PhoneAccountHandle makePstnPhoneAccountHandleWithPrefix(Phone phone, String prefix,
+                boolean isEmergency);
+    }
+
+    private PhoneUtilsProxy mPhoneUtilsProxy = new PhoneUtilsProxy() {
+        @Override
+        public int getSubIdForPhoneAccountHandle(PhoneAccountHandle accountHandle) {
+            return PhoneUtils.getSubIdForPhoneAccountHandle(accountHandle);
+        }
+
+        @Override
+        public PhoneAccountHandle makePstnPhoneAccountHandle(Phone phone) {
+            return PhoneUtils.makePstnPhoneAccountHandle(phone);
+        }
+
+        @Override
+        public PhoneAccountHandle makePstnPhoneAccountHandleWithPrefix(Phone phone, String prefix,
+                boolean isEmergency) {
+            return PhoneUtils.makePstnPhoneAccountHandleWithPrefix(phone, prefix, isEmergency);
+        }
+    };
+
+    /**
+     * PhoneNumberUtils dependencies for testing.
+     */
+    @VisibleForTesting
+    public interface PhoneNumberUtilsProxy {
+        String convertToEmergencyNumber(Context context, String number);
+    }
+
+    private PhoneNumberUtilsProxy mPhoneNumberUtilsProxy = new PhoneNumberUtilsProxy() {
+        @Override
+        public String convertToEmergencyNumber(Context context, String number) {
+            return PhoneNumberUtils.convertToEmergencyNumber(context, number);
+        }
+    };
+
+    /**
+     * PhoneSwitcher dependencies for testing.
+     */
+    @VisibleForTesting
+    public interface PhoneSwitcherProxy {
+        PhoneSwitcher getPhoneSwitcher();
+    }
+
+    private PhoneSwitcherProxy mPhoneSwitcherProxy = new PhoneSwitcherProxy() {
+        @Override
+        public PhoneSwitcher getPhoneSwitcher() {
+            return PhoneSwitcher.getInstance();
+        }
+    };
+
+    /**
+     * Factory for Handler creation in order to remove flakiness during t esting.
+     */
+    @VisibleForTesting
+    public interface HandlerFactory {
+        HandlerThread createHandlerThread(String name);
+        Handler createHandler(Looper looper);
+    }
+
+    private HandlerFactory mHandlerFactory = new HandlerFactory() {
+        @Override
+        public HandlerThread createHandlerThread(String name) {
+            return new HandlerThread(name);
+        }
+
+        @Override
+        public Handler createHandler(Looper looper) {
+            return new Handler(looper);
+        }
+    };
+
+    /**
+     * DisconnectCause depends on PhoneGlobals in order to get a system context. Mock out
+     * dependency for testing.
+     */
+    @VisibleForTesting
+    public interface DisconnectCauseFactory {
+        DisconnectCause toTelecomDisconnectCause(int telephonyDisconnectCause, String reason);
+        DisconnectCause toTelecomDisconnectCause(int telephonyDisconnectCause,
+                String reason, int phoneId);
+    }
+
+    private DisconnectCauseFactory mDisconnectCauseFactory = new DisconnectCauseFactory() {
+        @Override
+        public DisconnectCause toTelecomDisconnectCause(int telephonyDisconnectCause,
+                String reason) {
+            return DisconnectCauseUtil.toTelecomDisconnectCause(telephonyDisconnectCause, reason);
+        }
+
+        @Override
+        public DisconnectCause toTelecomDisconnectCause(int telephonyDisconnectCause, String reason,
+                int phoneId) {
+            return DisconnectCauseUtil.toTelecomDisconnectCause(telephonyDisconnectCause, reason,
+                    phoneId);
+        }
+    };
+
+    /**
+     * Overrides SubscriptionManager dependencies for testing.
+     */
     @VisibleForTesting
     public void setSubscriptionManagerProxy(SubscriptionManagerProxy proxy) {
         mSubscriptionManagerProxy = proxy;
     }
 
+    /**
+     * Overrides TelephonyManager dependencies for testing.
+     */
     @VisibleForTesting
     public void setTelephonyManagerProxy(TelephonyManagerProxy proxy) {
         mTelephonyManagerProxy = proxy;
     }
 
+    /**
+     * Overrides PhoneFactory dependencies for testing.
+     */
     @VisibleForTesting
     public void setPhoneFactoryProxy(PhoneFactoryProxy proxy) {
         mPhoneFactoryProxy = proxy;
     }
 
     /**
+     * Overrides configuration and settings dependencies for testing.
+     */
+    @VisibleForTesting
+    public void setDeviceState(DeviceState state) {
+        mDeviceState = state;
+    }
+
+    /**
+     * Overrides PhoneSwitcher dependencies for testing.
+     */
+    @VisibleForTesting
+    public void setPhoneSwitcherProxy(PhoneSwitcherProxy proxy) {
+        mPhoneSwitcherProxy = proxy;
+    }
+
+    /**
+     * Overrides PhoneNumberUtils dependencies for testing.
+     */
+    @VisibleForTesting
+    public void setPhoneNumberUtilsProxy(PhoneNumberUtilsProxy proxy) {
+        mPhoneNumberUtilsProxy = proxy;
+    }
+
+    /**
+     * Overrides PhoneUtils dependencies for testing.
+     */
+    @VisibleForTesting
+    public void setPhoneUtilsProxy(PhoneUtilsProxy proxy) {
+        mPhoneUtilsProxy = proxy;
+    }
+
+    /**
+     * Override Handler creation factory for testing.
+     */
+    @VisibleForTesting
+    public void setHandlerFactory(HandlerFactory handlerFactory) {
+        mHandlerFactory = handlerFactory;
+    }
+
+    /**
+     * Override DisconnectCause creation for testing.
+     */
+    @VisibleForTesting
+    public void setDisconnectCauseFactory(DisconnectCauseFactory factory) {
+        mDisconnectCauseFactory = factory;
+    }
+
+    /**
      * A listener to actionable events specific to the TelephonyConnection.
      */
     private final TelephonyConnection.TelephonyConnectionListener mTelephonyConnectionListener =
@@ -322,21 +487,26 @@
     @Override
     public void onCreate() {
         super.onCreate();
+        mImsConferenceController = new ImsConferenceController(
+                TelecomAccountRegistry.getInstance(this),
+                mTelephonyConnectionServiceProxy,
+                // FeatureFlagProxy; used to determine if standalone call emulation is enabled.
+                // TODO: Move to carrier config
+                () -> true);
         setTelephonyManagerProxy(new TelephonyManagerProxyImpl(getApplicationContext()));
         mExpectedComponentName = new ComponentName(this, this.getClass());
         mEmergencyTonePlayer = new EmergencyTonePlayer(this);
         TelecomAccountRegistry.getInstance(this).setTelephonyConnectionService(this);
         mHoldTracker = new HoldTracker();
-        mIsTtyEnabled = isTtyModeEnabled(getApplicationContext());
+        mIsTtyEnabled = mDeviceState.isTtyModeEnabled(this);
 
         IntentFilter intentFilter = new IntentFilter(
                 TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED);
         registerReceiver(mTtyBroadcastReceiver, intentFilter);
-
-        mHandlerThread = new HandlerThread("DdsSwitchHandlerThread");
+        mHandlerThread = mHandlerFactory.createHandlerThread("DdsSwitchHandlerThread");
         mHandlerThread.start();
         Looper looper = mHandlerThread.getLooper();
-        mDdsSwitchHandler = new Handler(looper);
+        mDdsSwitchHandler = mHandlerFactory.createHandler(looper);
     }
 
     @Override
@@ -356,7 +526,7 @@
         if (handle == null) {
             Log.d(this, "onCreateOutgoingConnection, handle is null");
             return Connection.createFailedConnection(
-                    DisconnectCauseUtil.toTelecomDisconnectCause(
+                    mDisconnectCauseFactory.toTelecomDisconnectCause(
                             android.telephony.DisconnectCause.NO_PHONE_NUMBER_SUPPLIED,
                             "No phone number supplied"));
         }
@@ -371,7 +541,7 @@
             if (phone == null) {
                 Log.d(this, "onCreateOutgoingConnection, phone is null");
                 return Connection.createFailedConnection(
-                        DisconnectCauseUtil.toTelecomDisconnectCause(
+                        mDisconnectCauseFactory.toTelecomDisconnectCause(
                                 android.telephony.DisconnectCause.OUT_OF_SERVICE,
                                 "Phone is null"));
             }
@@ -379,7 +549,7 @@
             if (TextUtils.isEmpty(number)) {
                 Log.d(this, "onCreateOutgoingConnection, no voicemail number set.");
                 return Connection.createFailedConnection(
-                        DisconnectCauseUtil.toTelecomDisconnectCause(
+                        mDisconnectCauseFactory.toTelecomDisconnectCause(
                                 android.telephony.DisconnectCause.VOICEMAIL_NUMBER_MISSING,
                                 "Voicemail scheme provided but no voicemail number set.",
                                 phone.getPhoneId()));
@@ -391,7 +561,7 @@
             if (!PhoneAccount.SCHEME_TEL.equals(scheme)) {
                 Log.d(this, "onCreateOutgoingConnection, Handle %s is not type tel", scheme);
                 return Connection.createFailedConnection(
-                        DisconnectCauseUtil.toTelecomDisconnectCause(
+                        mDisconnectCauseFactory.toTelecomDisconnectCause(
                                 android.telephony.DisconnectCause.INVALID_NUMBER,
                                 "Handle scheme is not type tel"));
             }
@@ -400,7 +570,7 @@
             if (TextUtils.isEmpty(number)) {
                 Log.d(this, "onCreateOutgoingConnection, unable to parse number");
                 return Connection.createFailedConnection(
-                        DisconnectCauseUtil.toTelecomDisconnectCause(
+                        mDisconnectCauseFactory.toTelecomDisconnectCause(
                                 android.telephony.DisconnectCause.INVALID_NUMBER,
                                 "Unable to parse number"));
             }
@@ -421,7 +591,7 @@
 
                 if (disableActivation) {
                     return Connection.createFailedConnection(
-                            DisconnectCauseUtil.toTelecomDisconnectCause(
+                            mDisconnectCauseFactory.toTelecomDisconnectCause(
                                     android.telephony.DisconnectCause
                                             .CDMA_ALREADY_ACTIVATED,
                                     "Tried to dial *228",
@@ -445,7 +615,8 @@
             // service.
             if (phone == null || phone.getServiceState().getState()
                     != ServiceState.STATE_IN_SERVICE) {
-                String convertedNumber = PhoneNumberUtils.convertToEmergencyNumber(this, number);
+                String convertedNumber = mPhoneNumberUtilsProxy.convertToEmergencyNumber(this,
+                        number);
                 if (!TextUtils.equals(convertedNumber, number)) {
                     Log.i(this, "onCreateOutgoingConnection, converted to emergency number");
                     number = convertedNumber;
@@ -456,8 +627,7 @@
         final String numberToDial = number;
 
 
-        final boolean isAirplaneModeOn = Settings.Global.getInt(getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_ON, 0) > 0;
+        final boolean isAirplaneModeOn = mDeviceState.isAirplaneModeOn(this);
 
         boolean needToTurnOnRadio = (isEmergencyNumber && (!isRadioOn() || isAirplaneModeOn))
                 || isRadioPowerDownOnBluetooth();
@@ -466,7 +636,7 @@
             final Uri resultHandle = handle;
             // By default, Connection based on the default Phone, since we need to return to Telecom
             // now.
-            final int originalPhoneType = PhoneFactory.getDefaultPhone().getPhoneType();
+            final int originalPhoneType = mPhoneFactoryProxy.getDefaultPhone().getPhoneType();
             final Connection resultConnection = getTelephonyConnection(request, numberToDial,
                     isEmergencyNumber, resultHandle, PhoneFactory.getDefaultPhone());
             if (mRadioOnHelper == null) {
@@ -583,12 +753,8 @@
      * Whether the cellular radio is power off because the device is on Bluetooth.
      */
     private boolean isRadioPowerDownOnBluetooth() {
-        final Context context = getApplicationContext();
-        final boolean allowed = context.getResources().getBoolean(
-                R.bool.config_allowRadioPowerDownOnBluetooth);
-        final int cellOn = Settings.Global.getInt(context.getContentResolver(),
-                Settings.Global.CELL_ON,
-                PhoneConstants.CELL_ON_FLAG);
+        final boolean allowed = mDeviceState.isRadioPowerDownAllowedOnBluetooth(this);
+        final int cellOn = mDeviceState.getCellOnStatus(this);
         return (allowed && cellOn == PhoneConstants.CELL_ON_FLAG && !isRadioOn());
     }
 
@@ -627,7 +793,7 @@
         } else {
             Log.w(this, "onCreateOutgoingConnection, failed to turn on radio");
             closeOrDestroyConnection(originalConnection,
-                    DisconnectCauseUtil.toTelecomDisconnectCause(
+                    mDisconnectCauseFactory.toTelecomDisconnectCause(
                             android.telephony.DisconnectCause.POWER_OFF,
                             "Failed to turn on radio."));
         }
@@ -652,11 +818,11 @@
             boolean noActiveSimCard = SubscriptionController.getInstance()
                     .getActiveSubInfoCount(phone.getContext().getOpPackageName()) == 0;
             // If there's no active sim card and the device is in emergency mode, use E account.
-            addExistingConnection(PhoneUtils.makePstnPhoneAccountHandleWithPrefix(
+            addExistingConnection(mPhoneUtilsProxy.makePstnPhoneAccountHandleWithPrefix(
                     phone, "", isEmergencyNumber && noActiveSimCard), repConnection);
             // Remove the old connection from Telecom after.
             closeOrDestroyConnection(connectionToEvaluate,
-                    DisconnectCauseUtil.toTelecomDisconnectCause(
+                    mDisconnectCauseFactory.toTelecomDisconnectCause(
                             android.telephony.DisconnectCause.OUTGOING_CANCELED,
                             "Reconnecting outgoing Emergency Call.",
                             phone.getPhoneId()));
@@ -685,7 +851,7 @@
 
         if (phone == null) {
             final Context context = getApplicationContext();
-            if (context.getResources().getBoolean(R.bool.config_checkSimStateBeforeOutgoingCall)) {
+            if (mDeviceState.shouldCheckSimStateBeforeOutgoingCall(this)) {
                 // Check SIM card state before the outgoing call.
                 // Start the SIM unlock activity if PIN_REQUIRED.
                 final Phone defaultPhone = mPhoneFactoryProxy.getDefaultPhone();
@@ -710,7 +876,7 @@
                         }
                     }
                     return Connection.createFailedConnection(
-                            DisconnectCauseUtil.toTelecomDisconnectCause(
+                            mDisconnectCauseFactory.toTelecomDisconnectCause(
                                     android.telephony.DisconnectCause.OUT_OF_SERVICE,
                                     "SIM_STATE_PIN_REQUIRED"));
                 }
@@ -718,7 +884,7 @@
 
             Log.d(this, "onCreateOutgoingConnection, phone is null");
             return Connection.createFailedConnection(
-                    DisconnectCauseUtil.toTelecomDisconnectCause(
+                    mDisconnectCauseFactory.toTelecomDisconnectCause(
                             android.telephony.DisconnectCause.OUT_OF_SERVICE, "Phone is null"));
         }
 
@@ -746,7 +912,7 @@
 
             if (!allowNonEmergencyCalls) {
                 return Connection.createFailedConnection(
-                        DisconnectCauseUtil.toTelecomDisconnectCause(
+                        mDisconnectCauseFactory.toTelecomDisconnectCause(
                                 android.telephony.DisconnectCause.CDMA_NOT_EMERGENCY,
                                 "Cannot make non-emergency call in ECM mode.",
                                 phone.getPhoneId()));
@@ -764,7 +930,7 @@
                         break;
                     } else {
                         return Connection.createFailedConnection(
-                                DisconnectCauseUtil.toTelecomDisconnectCause(
+                                mDisconnectCauseFactory.toTelecomDisconnectCause(
                                         android.telephony.DisconnectCause.OUT_OF_SERVICE,
                                         "ServiceState.STATE_OUT_OF_SERVICE",
                                         phone.getPhoneId()));
@@ -775,25 +941,24 @@
                         break;
                     }
                     return Connection.createFailedConnection(
-                            DisconnectCauseUtil.toTelecomDisconnectCause(
+                            mDisconnectCauseFactory.toTelecomDisconnectCause(
                                     android.telephony.DisconnectCause.POWER_OFF,
                                     "ServiceState.STATE_POWER_OFF",
                                     phone.getPhoneId()));
                 default:
                     Log.d(this, "onCreateOutgoingConnection, unknown service state: %d", state);
                     return Connection.createFailedConnection(
-                            DisconnectCauseUtil.toTelecomDisconnectCause(
+                            mDisconnectCauseFactory.toTelecomDisconnectCause(
                                     android.telephony.DisconnectCause.OUTGOING_FAILURE,
                                     "Unknown service state " + state,
                                     phone.getPhoneId()));
             }
         }
 
-        final Context context = getApplicationContext();
-        final boolean isTtyModeEnabled = isTtyModeEnabled(context);
+        final boolean isTtyModeEnabled = mDeviceState.isTtyModeEnabled(this);
         if (VideoProfile.isVideo(request.getVideoState()) && isTtyModeEnabled
                 && !isEmergencyNumber) {
-            return Connection.createFailedConnection(DisconnectCauseUtil.toTelecomDisconnectCause(
+            return Connection.createFailedConnection(mDisconnectCauseFactory.toTelecomDisconnectCause(
                     android.telephony.DisconnectCause.VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED,
                     null, phone.getPhoneId()));
         }
@@ -807,7 +972,7 @@
         // Check roaming status to see if we should block custom call forwarding codes
         if (blockCallForwardingNumberWhileRoaming(phone, number)) {
             return Connection.createFailedConnection(
-                    DisconnectCauseUtil.toTelecomDisconnectCause(
+                    mDisconnectCauseFactory.toTelecomDisconnectCause(
                             android.telephony.DisconnectCause.DIALED_CALL_FORWARDING_WHILE_ROAMING,
                             "Call forwarding while roaming",
                             phone.getPhoneId()));
@@ -819,7 +984,7 @@
                         request.getTelecomCallId());
         if (connection == null) {
             return Connection.createFailedConnection(
-                    DisconnectCauseUtil.toTelecomDisconnectCause(
+                    mDisconnectCauseFactory.toTelecomDisconnectCause(
                             android.telephony.DisconnectCause.OUTGOING_FAILURE,
                             "Invalid phone type",
                             phone.getPhoneId()));
@@ -852,7 +1017,7 @@
                 request.getAddress() == null ? null : request.getAddress().getSchemeSpecificPart());
         if (phone == null) {
             return Connection.createFailedConnection(
-                    DisconnectCauseUtil.toTelecomDisconnectCause(
+                    mDisconnectCauseFactory.toTelecomDisconnectCause(
                             android.telephony.DisconnectCause.ERROR_UNSPECIFIED,
                             "Phone is null"));
         }
@@ -861,7 +1026,7 @@
         if (!call.getState().isRinging()) {
             Log.i(this, "onCreateIncomingConnection, no ringing call");
             return Connection.createFailedConnection(
-                    DisconnectCauseUtil.toTelecomDisconnectCause(
+                    mDisconnectCauseFactory.toTelecomDisconnectCause(
                             android.telephony.DisconnectCause.INCOMING_MISSED,
                             "Found no ringing call",
                             phone.getPhoneId()));
@@ -882,6 +1047,7 @@
         if (connection == null) {
             return Connection.createCanceledConnection();
         } else {
+            connection.setTtyEnabled(mDeviceState.isTtyModeEnabled(getApplicationContext()));
             return connection;
         }
     }
@@ -1014,7 +1180,7 @@
                 request.getAddress() == null ? null : request.getAddress().getSchemeSpecificPart());
         if (phone == null) {
             return Connection.createFailedConnection(
-                    DisconnectCauseUtil.toTelecomDisconnectCause(
+                    mDisconnectCauseFactory.toTelecomDisconnectCause(
                             android.telephony.DisconnectCause.ERROR_UNSPECIFIED,
                             "Phone is null"));
         }
@@ -1267,7 +1433,7 @@
     }
 
     private void updatePhoneAccount(TelephonyConnection connection, Phone phone) {
-        PhoneAccountHandle pHandle = PhoneUtils.makePstnPhoneAccountHandle(phone);
+        PhoneAccountHandle pHandle = mPhoneUtilsProxy.makePstnPhoneAccountHandle(phone);
         // For ECall handling on MSIM, until the request reaches here (i.e PhoneApp), we don't know
         // on which phone account ECall can be placed. After deciding, we should notify Telecom of
         // the change so that the proper PhoneAccount can be displayed.
@@ -1354,7 +1520,7 @@
                     break;
             }
             connection.setTelephonyConnectionDisconnected(
-                    DisconnectCauseUtil.toTelecomDisconnectCause(cause, e.getMessage(),
+                    mDisconnectCauseFactory.toTelecomDisconnectCause(cause, e.getMessage(),
                             phone.getPhoneId()));
             connection.close();
             return;
@@ -1378,7 +1544,7 @@
             }
             Log.d(this, "placeOutgoingConnection, phone.dial returned null");
             connection.setTelephonyConnectionDisconnected(
-                    DisconnectCauseUtil.toTelecomDisconnectCause(telephonyDisconnectCause,
+                    mDisconnectCauseFactory.toTelecomDisconnectCause(telephonyDisconnectCause,
                             "Connection is null", phone.getPhoneId()));
             connection.close();
         } else {
@@ -1472,7 +1638,7 @@
     private Phone getPhoneForAccount(PhoneAccountHandle accountHandle, boolean isEmergency,
                                      @Nullable String emergencyNumberAddress) {
         Phone chosenPhone = null;
-        int subId = PhoneUtils.getSubIdForPhoneAccountHandle(accountHandle);
+        int subId = mPhoneUtilsProxy.getSubIdForPhoneAccountHandle(accountHandle);
         if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
             int phoneId = mSubscriptionManagerProxy.getPhoneId(subId);
             chosenPhone = mPhoneFactoryProxy.getPhone(phoneId);
@@ -1502,7 +1668,7 @@
             return possiblyOverrideDefaultDataForEmergencyCall(phone).get(
                     DEFAULT_DATA_SWITCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
         } catch (Exception e) {
-            Log.w(this, "onCreateOutgoingConn - delayDialForDdsSwitch exception= "
+            Log.w(this, "delayDialForDdsSwitch - exception= "
                     + e.getMessage());
             return false;
         }
@@ -1522,13 +1688,21 @@
      */
     private CompletableFuture<Boolean> possiblyOverrideDefaultDataForEmergencyCall(
             @NonNull Phone phone) {
-        TelephonyManager telephony = TelephonyManager.from(phone.getContext());
-        int phoneCount = telephony.getPhoneCount();
+        int phoneCount = mTelephonyManagerProxy.getPhoneCount();
         // Do not override DDS if this is a single SIM device.
         if (phoneCount <= PhoneConstants.MAX_PHONE_COUNT_SINGLE_SIM) {
             return CompletableFuture.completedFuture(Boolean.TRUE);
         }
 
+        // Do not switch Default data if this device supports emergency SUPL on non-DDS.
+        final boolean gnssSuplRequiresDefaultData =
+                mDeviceState.isSuplDdsSwitchRequiredForEmergencyCall(this);
+        if (!gnssSuplRequiresDefaultData) {
+            Log.d(this, "possiblyOverrideDefaultDataForEmergencyCall: not switching DDS, does not "
+                    + "require DDS switch.");
+            return CompletableFuture.completedFuture(Boolean.TRUE);
+        }
+
         CarrierConfigManager cfgManager = (CarrierConfigManager)
                 phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
         if (cfgManager == null) {
@@ -1537,34 +1711,41 @@
                     + "CarrierConfigManager");
             return CompletableFuture.completedFuture(Boolean.TRUE);
         }
-        // Only override default data if we are IN_SERVICE and on a home network. We don't want to
-        // perform a DDS switch of we are on a roaming network, where SUPL may not be available.
-        boolean isPhoneAvailableForEmergency = isAvailableForEmergencyCalls(phone);
+
+        // Only override default data if we are IN_SERVICE already.
+        if (!isAvailableForEmergencyCalls(phone)) {
+            Log.d(this, "possiblyOverrideDefaultDataForEmergencyCall: not switching DDS");
+            return CompletableFuture.completedFuture(Boolean.TRUE);
+        }
+
+        // Only override default data if we are not roaming, we do not want to switch onto a network
+        // that only supports data plane only (if we do not know).
         boolean isRoaming = phone.getServiceState().getVoiceRoaming();
-        if (!isPhoneAvailableForEmergency || isRoaming) {
-            Log.d(this, "possiblyOverrideDefaultDataForEmergencyCall: not switching DDS, avail = "
-                    + isPhoneAvailableForEmergency + ", roaming = " + isRoaming);
+        // In some roaming conditions, we know the roaming network doesn't support control plane
+        // fallback even though the home operator does. For these operators we will need to do a DDS
+        // switch anyway to make sure the SUPL request doesn't fail.
+        boolean roamingNetworkSupportsControlPlaneFallback = true;
+        String[] dataPlaneRoamPlmns = cfgManager.getConfigForSubId(phone.getSubId()).getStringArray(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY);
+        if (dataPlaneRoamPlmns != null && Arrays.asList(dataPlaneRoamPlmns).contains(
+                phone.getServiceState().getOperatorNumeric())) {
+            roamingNetworkSupportsControlPlaneFallback = false;
+        }
+        if (isRoaming && roamingNetworkSupportsControlPlaneFallback) {
+            Log.d(this, "possiblyOverrideDefaultDataForEmergencyCall: roaming network is assumed "
+                    + "to support CP fallback, not switching DDS.");
             return CompletableFuture.completedFuture(Boolean.TRUE);
         }
-
-        // Do not switch Default data if this device supports emergency SUPL on non-DDS.
-        final boolean gnssSuplRequiresDefaultData = phone.getContext().getResources().getBoolean(
-                R.bool.config_gnss_supl_requires_default_data_for_emergency);
-        if (!gnssSuplRequiresDefaultData) {
-            Log.d(this, "possiblyOverrideDefaultDataForEmergencyCall: not switching DDS, does not "
-                    + "require DDS switch.");
-            return CompletableFuture.completedFuture(Boolean.TRUE);
-        }
-
+        // Do not try to swap default data if we support CS fallback or it is assumed that the
+        // roaming network supports control plane fallback, we do not want to introduce
+        // a lag in emergency call setup time if possible.
         final boolean supportsCpFallback = cfgManager.getConfigForSubId(phone.getSubId())
                 .getInt(CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
                         CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_ONLY)
                 != CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY;
-        if (supportsCpFallback) {
+        if (supportsCpFallback && roamingNetworkSupportsControlPlaneFallback) {
             Log.d(this, "possiblyOverrideDefaultDataForEmergencyCall: not switching DDS, carrier "
                     + "supports CP fallback.");
-            // Do not try to swap default data if we support CS fallback, do not want to introduce
-            // a lag in emergency call setup time if possible.
             return CompletableFuture.completedFuture(Boolean.TRUE);
         }
 
@@ -1572,7 +1753,7 @@
         // CarrierConfig default if format fails.
         int extensionTime = 0;
         try {
-            extensionTime = Integer.valueOf(cfgManager.getConfigForSubId(phone.getSubId())
+            extensionTime = Integer.parseInt(cfgManager.getConfigForSubId(phone.getSubId())
                     .getString(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0"));
         } catch (NumberFormatException e) {
             // Just use default.
@@ -1581,12 +1762,13 @@
         try {
             Log.d(this, "possiblyOverrideDefaultDataForEmergencyCall: overriding DDS for "
                     + extensionTime + "seconds");
-            PhoneSwitcher.getInstance().overrideDefaultDataForEmergency(phone.getPhoneId(),
-                    extensionTime, modemResultFuture);
+            mPhoneSwitcherProxy.getPhoneSwitcher().overrideDefaultDataForEmergency(
+                    phone.getPhoneId(), extensionTime, modemResultFuture);
             // Catch all exceptions, we want to continue with emergency call if possible.
         } catch (Exception e) {
             Log.w(this, "possiblyOverrideDefaultDataForEmergencyCall: exception = "
                     + e.getMessage());
+            modemResultFuture = CompletableFuture.completedFuture(Boolean.FALSE);
         }
         return modemResultFuture;
     }
@@ -1902,13 +2084,6 @@
         return null; // null means nothing went wrong, and call should continue.
     }
 
-    private boolean isTtyModeEnabled(Context context) {
-        return (android.provider.Settings.Secure.getInt(
-                context.getContentResolver(),
-                android.provider.Settings.Secure.PREFERRED_TTY_MODE,
-                TelecomManager.TTY_MODE_OFF) != TelecomManager.TTY_MODE_OFF);
-    }
-
     /**
      * For outgoing dialed calls, potentially send a ConnectionEvent if the user is on WFC and is
      * dialing an international number.
diff --git a/tests/Android.bp b/tests/Android.bp
index 7c51a0d..22b40b5 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -20,6 +20,7 @@
     srcs: ["src/**/*.java"],
 
     libs: [
+        "android.test.mock",
         "android.test.runner",
         "telephony-common",
         "android.test.base",
diff --git a/tests/src/com/android/TelephonyTestBase.java b/tests/src/com/android/TelephonyTestBase.java
index d30ae6b..01267d8 100644
--- a/tests/src/com/android/TelephonyTestBase.java
+++ b/tests/src/com/android/TelephonyTestBase.java
@@ -16,13 +16,10 @@
 
 package com.android;
 
-import android.content.Context;
 import android.os.Handler;
 import android.os.Looper;
 import android.util.Log;
 
-import androidx.test.InstrumentationRegistry;
-
 import org.mockito.MockitoAnnotations;
 
 import java.util.concurrent.CountDownLatch;
@@ -33,11 +30,11 @@
  */
 public class TelephonyTestBase {
 
-    protected Context mContext;
+    protected TestContext mContext;
 
     public void setUp() throws Exception {
-        mContext = InstrumentationRegistry.getTargetContext();
         MockitoAnnotations.initMocks(this);
+        mContext = new TestContext();
         // Set up the looper if it does not exist on the test thread.
         if (Looper.myLooper() == null) {
             Looper.prepare();
@@ -86,4 +83,8 @@
             Log.e("TelephonyTestBase", "InterruptedException while waiting: " + e);
         }
     }
+
+    protected TestContext getTestContext() {
+        return mContext;
+    }
 }
diff --git a/tests/src/com/android/TestContext.java b/tests/src/com/android/TestContext.java
new file mode 100644
index 0000000..776ec6a
--- /dev/null
+++ b/tests/src/com/android/TestContext.java
@@ -0,0 +1,122 @@
+/*
+ * 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;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.PersistableBundle;
+import android.telecom.TelecomManager;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.test.mock.MockContext;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+public class TestContext extends MockContext {
+
+    @Mock CarrierConfigManager mMockCarrierConfigManager;
+    @Mock TelecomManager mMockTelecomManager;
+    @Mock TelephonyManager mMockTelephonyManager;
+    @Mock SubscriptionManager mMockSubscriptionManager;
+
+    private PersistableBundle mCarrierConfig = new PersistableBundle();
+
+    public TestContext() {
+        MockitoAnnotations.initMocks(this);
+        doReturn(mCarrierConfig).when(mMockCarrierConfigManager).getConfigForSubId(anyInt());
+    }
+
+    @Override
+    public Context getApplicationContext() {
+        return this;
+    }
+
+    @Override
+    public String getPackageName() {
+        return "com.android.phone.tests";
+    }
+
+    @Override
+    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+        return null;
+    }
+
+    @Override
+    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, int flags) {
+        return null;
+    }
+
+    @Override
+    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
+            String broadcastPermission, Handler scheduler) {
+        return null;
+    }
+
+    @Override
+    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
+            String broadcastPermission, Handler scheduler, int flags) {
+        return null;
+    }
+
+    @Override
+    public Object getSystemService(String name) {
+        switch (name) {
+            case (Context.CARRIER_CONFIG_SERVICE) : {
+                return mMockCarrierConfigManager;
+            }
+            case (Context.TELECOM_SERVICE) : {
+                return mMockTelecomManager;
+            }
+            case (Context.TELEPHONY_SERVICE) : {
+                return mMockTelephonyManager;
+            }
+            case (Context.TELEPHONY_SUBSCRIPTION_SERVICE) : {
+                return mMockSubscriptionManager;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public String getSystemServiceName(Class<?> serviceClass) {
+        if (serviceClass == CarrierConfigManager.class) {
+            return Context.CARRIER_CONFIG_SERVICE;
+        }
+        if (serviceClass == TelecomManager.class) {
+            return Context.TELECOM_SERVICE;
+        }
+        if (serviceClass == TelephonyManager.class) {
+            return Context.TELEPHONY_SERVICE;
+        }
+        if (serviceClass == SubscriptionManager.class) {
+            return Context.TELEPHONY_SUBSCRIPTION_SERVICE;
+        }
+        return null;
+    }
+
+    public PersistableBundle getCarrierConfig() {
+        return mCarrierConfig;
+    }
+}
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index bcc4fd3..6e11e51 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -17,10 +17,13 @@
 package com.android.services.telephony;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.Assert.fail;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doReturn;
@@ -29,26 +32,32 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.content.ComponentName;
 import android.content.Context;
 import android.net.Uri;
 import android.os.AsyncResult;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.telecom.ConnectionRequest;
 import android.telecom.DisconnectCause;
+import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
+import android.telephony.CarrierConfigManager;
 import android.telephony.RadioAccessFamily;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
+import android.telephony.emergency.EmergencyNumber;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.TelephonyTestBase;
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.Connection;
 import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneSwitcher;
 import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
 
@@ -60,6 +69,8 @@
 import org.mockito.Mock;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -73,20 +84,72 @@
     private static final int SLOT_0_PHONE_ID = 0;
     private static final int SLOT_1_PHONE_ID = 1;
 
+    private static final ComponentName TEST_COMPONENT_NAME = new ComponentName(
+            "com.android.phone.tests", TelephonyConnectionServiceTest.class.getName());
+    private static final String TEST_ACCOUNT_ID1 = "id1";
+    private static final String TEST_ACCOUNT_ID2 = "id2";
+    private static final PhoneAccountHandle PHONE_ACCOUNT_HANDLE_1 = new PhoneAccountHandle(
+            TEST_COMPONENT_NAME, TEST_ACCOUNT_ID1);
+    private static final PhoneAccountHandle PHONE_ACCOUNT_HANDLE_2 = new PhoneAccountHandle(
+            TEST_COMPONENT_NAME, TEST_ACCOUNT_ID2);
+    private static final Uri TEST_ADDRESS = Uri.parse("tel:+16505551212");
+
     @Mock TelephonyConnectionService.TelephonyManagerProxy mTelephonyManagerProxy;
     @Mock TelephonyConnectionService.SubscriptionManagerProxy mSubscriptionManagerProxy;
     @Mock TelephonyConnectionService.PhoneFactoryProxy mPhoneFactoryProxy;
+    @Mock DeviceState mDeviceState;
+    @Mock TelephonyConnectionService.PhoneSwitcherProxy mPhoneSwitcherProxy;
+    @Mock TelephonyConnectionService.PhoneNumberUtilsProxy mPhoneNumberUtilsProxy;
+    @Mock TelephonyConnectionService.PhoneUtilsProxy mPhoneUtilsProxy;
+    @Mock TelephonyConnectionService.HandlerFactory mHandlerFactory;
+    @Mock TelephonyConnectionService.DisconnectCauseFactory mDisconnectCauseFactory;
+    @Mock Handler mMockHandler;
     @Mock EmergencyNumberTracker mEmergencyNumberTracker;
+    @Mock PhoneSwitcher mPhoneSwitcher;
 
-    TelephonyConnectionService mTestConnectionService;
+    private static class TestTelephonyConnectionService extends TelephonyConnectionService {
+
+        private final Context mContext;
+
+        TestTelephonyConnectionService(Context context) {
+            mContext = context;
+        }
+
+        @Override
+        public void onCreate() {
+            // attach test context.
+            attachBaseContext(mContext);
+            super.onCreate();
+        }
+    }
+
+    private TelephonyConnectionService mTestConnectionService;
 
     @Before
     public void setUp() throws Exception {
         super.setUp();
-        mTestConnectionService = new TelephonyConnectionService();
+        mTestConnectionService = new TestTelephonyConnectionService(mContext);
         mTestConnectionService.setPhoneFactoryProxy(mPhoneFactoryProxy);
-        mTestConnectionService.setTelephonyManagerProxy(mTelephonyManagerProxy);
         mTestConnectionService.setSubscriptionManagerProxy(mSubscriptionManagerProxy);
+        // Set configurations statically
+        doReturn(false).when(mDeviceState).shouldCheckSimStateBeforeOutgoingCall(any());
+        mTestConnectionService.setPhoneSwitcherProxy(mPhoneSwitcherProxy);
+        doReturn(mPhoneSwitcher).when(mPhoneSwitcherProxy).getPhoneSwitcher();
+        mTestConnectionService.setPhoneNumberUtilsProxy(mPhoneNumberUtilsProxy);
+        mTestConnectionService.setPhoneUtilsProxy(mPhoneUtilsProxy);
+        HandlerThread mockHandlerThread = mock(HandlerThread.class);
+        doReturn(mockHandlerThread).when(mHandlerFactory).createHandlerThread(anyString());
+        doReturn(null).when(mockHandlerThread).getLooper();
+        doReturn(mMockHandler).when(mHandlerFactory).createHandler(any());
+        mTestConnectionService.setHandlerFactory(mHandlerFactory);
+        mTestConnectionService.setDeviceState(mDeviceState);
+        doReturn(new DisconnectCause(DisconnectCause.UNKNOWN)).when(mDisconnectCauseFactory)
+                .toTelecomDisconnectCause(anyInt(), any());
+        doReturn(new DisconnectCause(DisconnectCause.UNKNOWN)).when(mDisconnectCauseFactory)
+                .toTelecomDisconnectCause(anyInt(), any(), anyInt());
+        mTestConnectionService.setDisconnectCauseFactory(mDisconnectCauseFactory);
+        mTestConnectionService.onCreate();
+        mTestConnectionService.setTelephonyManagerProxy(mTelephonyManagerProxy);
     }
 
     @After
@@ -558,7 +621,6 @@
      * called.
      */
     @Test
-    @FlakyTest
     @SmallTest
     public void testRetryOutgoingOriginalConnection_redialTempFailOneSlot() {
         TestTelephonyConnection c = new TestTelephonyConnection();
@@ -567,7 +629,7 @@
         List<Phone> phones = new ArrayList<>(1);
         phones.add(slot0Phone);
         setPhones(phones);
-        c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
+        c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
 
         mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
 
@@ -590,7 +652,6 @@
      * not called.
      */
     @Test
-    @FlakyTest
     @SmallTest
     public void testRetryOutgoingOriginalConnection_redialPermFailOneSlot() {
         TestTelephonyConnection c = new TestTelephonyConnection();
@@ -599,7 +660,7 @@
         List<Phone> phones = new ArrayList<>(1);
         phones.add(slot0Phone);
         setPhones(phones);
-        c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
+        c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
 
         mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
 
@@ -624,7 +685,6 @@
      * PhoneAccount.
      */
     @Test
-    @FlakyTest
     @SmallTest
     public void testRetryOutgoingOriginalConnection_redialTempFailTwoSlot() {
         TestTelephonyConnection c = new TestTelephonyConnection();
@@ -633,11 +693,15 @@
         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
                 false /*isEmergencyOnly*/);
         setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
-        c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
+        c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
         List<Phone> phones = new ArrayList<>(2);
         phones.add(slot0Phone);
         phones.add(slot1Phone);
         setPhones(phones);
+        doReturn(PHONE_ACCOUNT_HANDLE_1).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
+                slot0Phone);
+        doReturn(PHONE_ACCOUNT_HANDLE_2).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
+                slot1Phone);
 
         mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
 
@@ -662,7 +726,6 @@
      * PhoneAccount.
      */
     @Test
-    @FlakyTest
     @SmallTest
     public void testRetryOutgoingOriginalConnection_redialPermFailTwoSlot() {
         TestTelephonyConnection c = new TestTelephonyConnection();
@@ -671,11 +734,15 @@
         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
                 false /*isEmergencyOnly*/);
         setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
-        c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
+        c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
         List<Phone> phones = new ArrayList<>(2);
         phones.add(slot0Phone);
         phones.add(slot1Phone);
         setPhones(phones);
+        doReturn(PHONE_ACCOUNT_HANDLE_1).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
+                slot0Phone);
+        doReturn(PHONE_ACCOUNT_HANDLE_2).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
+                slot1Phone);
 
         mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
 
@@ -700,7 +767,6 @@
      * notified of this twice.
      */
     @Test
-    @FlakyTest
     @SmallTest
     public void testRetryOutgoingOriginalConnection_redialTempFailTwoSlot_twoFailure() {
         TestTelephonyConnection c = new TestTelephonyConnection();
@@ -709,11 +775,15 @@
         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
                 false /*isEmergencyOnly*/);
         setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
-        c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
+        c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
         List<Phone> phones = new ArrayList<>(2);
         phones.add(slot0Phone);
         phones.add(slot1Phone);
         setPhones(phones);
+        doReturn(PHONE_ACCOUNT_HANDLE_1).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
+                slot0Phone);
+        doReturn(PHONE_ACCOUNT_HANDLE_2).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
+                slot1Phone);
 
         // First Temporary failure
         mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
@@ -752,7 +822,6 @@
      * notified of the change to slot 1.
      */
     @Test
-    @FlakyTest
     @SmallTest
     public void testRetryOutgoingOriginalConnection_redialPermFailTwoSlot_twoFailure() {
         TestTelephonyConnection c = new TestTelephonyConnection();
@@ -761,11 +830,15 @@
         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
                 false /*isEmergencyOnly*/);
         setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
-        c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
+        c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
         List<Phone> phones = new ArrayList<>(2);
         phones.add(slot0Phone);
         phones.add(slot1Phone);
         setPhones(phones);
+        doReturn(PHONE_ACCOUNT_HANDLE_1).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
+                slot0Phone);
+        doReturn(PHONE_ACCOUNT_HANDLE_2).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
+                slot1Phone);
 
         // First Permanent failure
         mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
@@ -803,11 +876,7 @@
         // registration to occur.
         Phone phone = c.getPhone();
         c.setOriginalConnection(c.getOriginalConnection());
-
-        // Use a real context since the method SubscriptionManager.getResourcesForSubId()
-        // needs to interact with a real context.
-        Context targetContext = InstrumentationRegistry.getTargetContext();
-        doReturn(targetContext).when(phone).getContext();
+        doReturn(mContext).when(phone).getContext();
 
         // When the registration occurs, we'll capture the handler and message so we can post our
         // own messages to it.
@@ -844,6 +913,239 @@
                 extras.getInt(TelephonyManager.EXTRA_NOTIFICATION_CODE));
     }
 
+    /**
+     * Test that the TelephonyConnectionService successfully performs a DDS switch before a call
+     * when we are not roaming and the carrier only supports SUPL over the data plane.
+     */
+    @Test
+    @SmallTest
+    public void testCreateOutgoingEmergencyConnection_delayDial_carrierconfig_dds() {
+        Phone testPhone = setupConnectionServiceForDelayDial();
+        Runnable delayDialRunnable = verifyRunnablePosted();
+
+        // Setup test to not support SUPL on the non-DDS subscription
+        doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
+        getTestContext().getCarrierConfig().putStringArray(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
+                null);
+        testPhone.getServiceState().setRoaming(false);
+        getTestContext().getCarrierConfig().putInt(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
+                CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY);
+        getTestContext().getCarrierConfig().putString(
+                CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "150");
+        delayDialRunnable.run();
+
+        verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(0) /*phoneId*/ ,
+                eq(150) /*extensionTime*/, any());
+    }
+
+    /**
+     * Test that the TelephonyConnectionService does not perform a DDS switch when the carrier
+     * supports control-plane fallback.
+     */
+    @Test
+    @SmallTest
+    public void testCreateOutgoingEmergencyConnection_delayDial_nocarrierconfig() {
+        Phone testPhone = setupConnectionServiceForDelayDial();
+        Runnable delayDialRunnable = verifyRunnablePosted();
+
+        // Setup test to not support SUPL on the non-DDS subscription
+        doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
+        getTestContext().getCarrierConfig().putStringArray(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
+                null);
+        testPhone.getServiceState().setRoaming(false);
+        getTestContext().getCarrierConfig().putInt(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
+                CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK);
+        getTestContext().getCarrierConfig().putString(
+                CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
+        delayDialRunnable.run();
+
+        verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any());
+    }
+
+    /**
+     * Test that the TelephonyConnectionService does not perform a DDS switch when the carrier
+     * supports control-plane fallback.
+     */
+    @Test
+    @SmallTest
+    public void testCreateOutgoingEmergencyConnection_delayDial_supportsuplondds() {
+        Phone testPhone = setupConnectionServiceForDelayDial();
+        Runnable delayDialRunnable = verifyRunnablePosted();
+
+        // If the non-DDS supports SUPL, dont switch data
+        doReturn(false).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
+        getTestContext().getCarrierConfig().putStringArray(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
+                null);
+        testPhone.getServiceState().setRoaming(false);
+        getTestContext().getCarrierConfig().putInt(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
+                CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY);
+        getTestContext().getCarrierConfig().putString(
+                CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
+        delayDialRunnable.run();
+
+        verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any());
+    }
+
+    /**
+     * Test that the TelephonyConnectionService does not perform a DDS switch when the carrier does
+     * not support control-plane fallback CarrierConfig while roaming.
+     */
+    @Test
+    @SmallTest
+    public void testCreateOutgoingEmergencyConnection_delayDial_roaming_nocarrierconfig() {
+        Phone testPhone = setupConnectionServiceForDelayDial();
+        Runnable delayDialRunnable = verifyRunnablePosted();
+
+        // Setup test to not support SUPL on the non-DDS subscription
+        doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
+        getTestContext().getCarrierConfig().putStringArray(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
+                null);
+        testPhone.getServiceState().setRoaming(true);
+        getTestContext().getCarrierConfig().putInt(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
+                CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY);
+        getTestContext().getCarrierConfig().putString(
+                CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
+        delayDialRunnable.run();
+
+        verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any());
+    }
+
+    /**
+     * Test that the TelephonyConnectionService does perform a DDS switch even though the carrier
+     * supports control-plane fallback CarrierConfig and the roaming partner is configured to look
+     * like a home network.
+     */
+    @Test
+    @SmallTest
+    public void testCreateOutgoingEmergencyConnection_delayDial_roamingcarrierconfig() {
+        Phone testPhone = setupConnectionServiceForDelayDial();
+        Runnable delayDialRunnable = verifyRunnablePosted();
+
+        // Setup voice roaming scenario
+        String testRoamingOperator = "001001";
+        // In some roaming conditions, we are not technically "roaming"
+        testPhone.getServiceState().setRoaming(false);
+        testPhone.getServiceState().setOperatorName("TestTel", "TestTel", testRoamingOperator);
+        // Setup test to not support SUPL on the non-DDS subscription
+        doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
+        String[] roamingPlmns = new String[1];
+        roamingPlmns[0] = testRoamingOperator;
+        getTestContext().getCarrierConfig().putStringArray(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
+                roamingPlmns);
+        getTestContext().getCarrierConfig().putInt(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
+                CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK);
+        getTestContext().getCarrierConfig().putString(
+                CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
+        delayDialRunnable.run();
+
+        verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(0) /*phoneId*/ ,
+                eq(0) /*extensionTime*/, any());
+    }
+
+    /**
+     * Test that the TelephonyConnectionService does perform a DDS switch even though the carrier
+     * supports control-plane fallback CarrierConfig if we are roaming and the roaming partner is
+     * configured to use data plane only SUPL.
+     */
+    @Test
+    @SmallTest
+    public void testCreateOutgoingEmergencyConnection_delayDial__roaming_roamingcarrierconfig() {
+        Phone testPhone = setupConnectionServiceForDelayDial();
+        Runnable delayDialRunnable = verifyRunnablePosted();
+
+        // Setup voice roaming scenario
+        String testRoamingOperator = "001001";
+        testPhone.getServiceState().setRoaming(true);
+        testPhone.getServiceState().setOperatorName("TestTel", "TestTel", testRoamingOperator);
+        // Setup test to not support SUPL on the non-DDS subscription
+        doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
+        String[] roamingPlmns = new String[1];
+        roamingPlmns[0] = testRoamingOperator;
+        getTestContext().getCarrierConfig().putStringArray(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
+                roamingPlmns);
+        getTestContext().getCarrierConfig().putInt(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
+                CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK);
+        getTestContext().getCarrierConfig().putString(
+                CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
+        delayDialRunnable.run();
+
+        verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(0) /*phoneId*/ ,
+                eq(0) /*extensionTime*/, any());
+    }
+
+    /**
+     * Set up a mock MSIM device with TEST_ADDRESS set as an emergency number.
+     * @return the Phone associated with slot 0.
+     */
+    private Phone setupConnectionServiceForDelayDial() {
+        ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
+                .setAccountHandle(PHONE_ACCOUNT_HANDLE_1)
+                .setAddress(TEST_ADDRESS)
+                .build();
+        Phone testPhone0 = makeTestPhone(0 /*phoneId*/, ServiceState.STATE_IN_SERVICE,
+                false /*isEmergencyOnly*/);
+        Phone testPhone1 = makeTestPhone(1 /*phoneId*/, ServiceState.STATE_OUT_OF_SERVICE,
+                false /*isEmergencyOnly*/);
+        List<Phone> phones = new ArrayList<>(2);
+        doReturn(true).when(testPhone0).isRadioOn();
+        doReturn(true).when(testPhone1).isRadioOn();
+        phones.add(testPhone0);
+        phones.add(testPhone1);
+        setPhones(phones);
+        setupHandleToPhoneMap(PHONE_ACCOUNT_HANDLE_1, testPhone0);
+        setupDeviceConfig(testPhone0, testPhone1, 1);
+        doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(
+                TEST_ADDRESS.getSchemeSpecificPart());
+        HashMap<Integer, List<EmergencyNumber>> emergencyNumbers = new HashMap<>(1);
+        List<EmergencyNumber> numbers = new ArrayList<>();
+        numbers.add(setupEmergencyNumber(TEST_ADDRESS));
+        emergencyNumbers.put(0 /*subId*/, numbers);
+        doReturn(emergencyNumbers).when(mTelephonyManagerProxy).getCurrentEmergencyNumberList();
+        doReturn(2).when(mTelephonyManagerProxy).getPhoneCount();
+
+        android.telecom.Connection testConnection = mTestConnectionService
+                .onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1, connectionRequest);
+        assertNotNull("test connection was not set up correctly.", testConnection);
+
+        return testPhone0;
+    }
+
+    private Runnable verifyRunnablePosted() {
+        ArgumentCaptor<Message> runnableCaptor = ArgumentCaptor.forClass(Message.class);
+        verify(mMockHandler).sendMessageDelayed(runnableCaptor.capture(), anyLong());
+        assertNotNull("Invalid Message created", runnableCaptor.getValue());
+        Runnable runnable = runnableCaptor.getValue().getCallback();
+        assertNotNull("sendMessageDelayed never occurred.", runnableCaptor);
+        return runnable;
+    }
+
+    private EmergencyNumber setupEmergencyNumber(Uri address) {
+        return new EmergencyNumber(address.getSchemeSpecificPart(), "", "",
+        EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
+        Collections.emptyList(),
+        EmergencyNumber.EMERGENCY_NUMBER_SOURCE_SIM,
+        EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY);
+    }
+
+    private void setupHandleToPhoneMap(PhoneAccountHandle handle,  Phone phone) {
+        // use subId 0
+        when(mPhoneUtilsProxy.getSubIdForPhoneAccountHandle(handle)).thenReturn(0);
+        when(mSubscriptionManagerProxy.getPhoneId(0)).thenReturn(0);
+        when(mPhoneFactoryProxy.getPhone(0)).thenReturn(phone);
+    }
+
     private AsyncResult getSuppServiceNotification(int notificationType, int code) {
         SuppServiceNotification notification = new SuppServiceNotification();
         notification.notificationType = notificationType;
@@ -856,6 +1158,7 @@
         ServiceState testServiceState = new ServiceState();
         testServiceState.setState(serviceState);
         testServiceState.setEmergencyOnly(isEmergencyOnly);
+        when(phone.getContext()).thenReturn(mContext);
         when(phone.getServiceState()).thenReturn(testServiceState);
         when(phone.getPhoneId()).thenReturn(phoneId);
         when(phone.getDefaultPhone()).thenReturn(phone);
diff --git a/tests/src/com/android/services/telephony/TestTelephonyConnection.java b/tests/src/com/android/services/telephony/TestTelephonyConnection.java
index 593494b..5b31c0f 100644
--- a/tests/src/com/android/services/telephony/TestTelephonyConnection.java
+++ b/tests/src/com/android/services/telephony/TestTelephonyConnection.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.os.Bundle;
+import android.os.PersistableBundle;
 import android.telecom.PhoneAccountHandle;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -135,6 +136,28 @@
         // Do nothing since the original connection is mock object
     }
 
+    @Override
+    public PersistableBundle getCarrierConfig() {
+        // Depends on PhoneGlobals for context in TelephonyConnection, do not implement during
+        // testing.
+        return new PersistableBundle();
+    }
+
+    @Override
+    public CharSequence getResourceText(int messageId) {
+        return "TEST";
+    }
+
+    @Override
+    public String getResourceString(int id) {
+        return "TEST";
+    }
+
+    @Override
+    void refreshConferenceSupported() {
+        // Requires ImsManager dependencies, do not implement during testing.
+    }
+
     public int getNotifyPhoneAccountChangedCount() {
         return mNotifyPhoneAccountChangedCount;
     }