Merge "Modify theme to DialerSettingsLight"
diff --git a/Android.bp b/Android.bp
index 76e910f..a06d5ef 100644
--- a/Android.bp
+++ b/Android.bp
@@ -22,7 +22,6 @@
         "telephony-common",
         "voip-common",
         "ims-common",
-        "org.apache.http.legacy",
         "libprotobuf-java-lite",
         "unsupportedappusage",
     ],
@@ -32,10 +31,10 @@
         "androidx.preference_preference",
         "androidx.recyclerview_recyclerview",
         "androidx.legacy_legacy-preference-v14",
-        "guava",
-        "volley",
         "android-support-annotations",
         "com.android.phone.common-lib",
+        "guava",
+        "PlatformProperties",
     ],
 
     srcs: [
@@ -79,4 +78,4 @@
     proto: {
         type: "lite",
     },
-}
\ No newline at end of file
+}
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 59c1775..a7c2073 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -32,10 +32,8 @@
     <protected-broadcast android:name="android.intent.action.EMERGENCY_CALL_STATE_CHANGED" />
     <protected-broadcast android:name="android.intent.action.SIG_STR" />
     <protected-broadcast android:name="android.intent.action.ANY_DATA_STATE" />
-    <protected-broadcast android:name="android.intent.action.DATA_CONNECTION_FAILED" />
     <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="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" />
@@ -77,7 +75,7 @@
     <protected-broadcast android:name= "com.android.imsconnection.DISCONNECTED" />
     <protected-broadcast android:name= "com.android.intent.action.IMS_FEATURE_CHANGED" />
     <protected-broadcast android:name= "com.android.intent.action.IMS_CONFIG_CHANGED" />
-    <protected-broadcast android:name= "com.android.ims.REGISTRATION_ERROR" />
+    <protected-broadcast android:name= "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR" />
     <protected-broadcast android:name= "com.android.phone.vvm.omtp.sms.REQUEST_SENT" />
     <protected-broadcast android:name= "com.android.phone.vvm.ACTION_VISUAL_VOICEMAIL_SERVICE_EVENT" />
     <protected-broadcast android:name= "com.android.internal.telephony.CARRIER_VVM_PACKAGE_INSTALLED" />
@@ -95,6 +93,9 @@
     <!-- For Vendor Debugging in Telephony -->
     <protected-broadcast android:name="android.telephony.action.ANOMALY_REPORTED" />
 
+    <protected-broadcast android:name= "android.intent.action.SUBSCRIPTION_INFO_RECORD_ADDED" />
+    <protected-broadcast android:name= "android.intent.action.ACTION_MANAGED_ROAMING_IND" />
+
     <!-- Allows granting runtime permissions to telephony related components. -->
     <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS" />
 
@@ -130,8 +131,8 @@
     <uses-permission android:name="android.permission.WRITE_SMS" />
     <uses-permission android:name="android.permission.SEND_SMS" />
     <uses-permission android:name="android.permission.SEND_RESPOND_VIA_MESSAGE" />
-    <uses-permission android:name="android.permission.SET_TIME" />
     <uses-permission android:name="android.permission.SET_TIME_ZONE" />
+    <uses-permission android:name="android.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
     <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
@@ -210,6 +211,7 @@
          ACTION_SIM_SLOT_STATUS_CHANGED broadcast to start activities
          from the background.  -->
     <uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
+    <uses-permission android:name="android.permission.NETWORK_STATS_PROVIDER" />
 
     <application android:name="PhoneApp"
             android:persistent="true"
@@ -243,6 +245,15 @@
                 <category android:name="android.intent.category.DEFAULT" />
                 <data android:scheme="tel" />
             </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.DIAL_EMERGENCY" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.DIAL_EMERGENCY" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="tel" />
+            </intent-filter>
         </activity>
 
         <activity android:name="ADNList" />
@@ -299,6 +310,15 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="CdmaCallForwardOptions"
+                android:label="@string/labelCF"
+                android:configChanges="orientation|screenSize|keyboardHidden"
+                android:theme="@style/DialerSettingsLight">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="GsmUmtsCallBarringOptions"
                 android:label="@string/labelCallBarring"
                 android:configChanges="orientation|screenSize|keyboardHidden"
@@ -500,7 +520,7 @@
 
         <receiver android:name="com.android.services.telephony.sip.SipIncomingCallReceiver">
             <intent-filter>
-                <action android:name="com.android.phone.SIP_INCOMING_CALL" />
+                <action android:name="android.net.sip.action.SIP_INCOMING_CALL" />
             </intent-filter>
         </receiver>
 
@@ -531,6 +551,12 @@
                 android:uiOptions="splitActionBarWhenNarrow">
         </activity>
 
+        <service android:name="com.android.services.telephony.sip.components.TelephonySipService">
+            <intent-filter>
+                <action android:name="android.net.sip.action.START_SIP" />
+            </intent-filter>
+        </service>
+
         <!-- End SIP -->
 
         <activity android:name="MMIDialogActivity"
@@ -623,5 +649,33 @@
                 <action android:name="android.telephony.data.DataService" />
             </intent-filter>
         </service>
+
+        <provider
+            android:name="ServiceStateProvider"
+            android:authorities="service-state"
+            android:exported="true"
+            android:multiprocess="false"
+            android:singleUser="true"
+            android:writePermission="android.permission.MODIFY_PHONE_STATE"/>
+
+        <activity
+            android:name=".settings.RadioInfo"
+            android:label="@string/phone_info_label"
+            android:theme="@style/Theme.AppCompat.DayNight">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEVELOPMENT_PREFERENCE" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".settings.BandMode"
+                  android:label="@string/band_mode_title"
+                  android:theme="@style/Theme.AppCompat.DayNight">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.VOICE_LAUNCH" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 22845e0..3aa8121 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -50,3 +50,6 @@
 $(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)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/apex/com.android.telephony/javalib/telephony-common.jar)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/apex/com.android.telephony/javalib/ims-common.jar)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/apex/com.android.telephony.apex)
\ No newline at end of file
diff --git a/OWNERS b/OWNERS
index 5be6fe5..3059d4d 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,14 +1,15 @@
 amitmahajan@google.com
 breadley@google.com
 fionaxu@google.com
-hallliu@google.com
 jackyu@google.com
+hallliu@google.com
 rgreenwalt@google.com
 tgunn@google.com
-refuhoo@google.com
-mpq@google.com
 jminjie@google.com
 shuoq@google.com
-paulye@google.com
+refuhoo@google.com
 nazaninb@google.com
-sarahchin@google.com
\ No newline at end of file
+sarahchin@google.com
+dbright@google.com
+xiaotonj@google.com
+
diff --git a/apex/Android.bp b/apex/Android.bp
index f9e4b67..a7137d9 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -4,7 +4,7 @@
     // optional. if unspecified, a default one is auto-generated
     androidManifest: "AndroidManifest.xml",
 
-    java_libs: ["telephony-common", "ims-common"],
+    //java_libs: ["telephony-common", "ims-common", "voip-common"],
     //apps: ["TeleService", "StkLib", "ONSLib"],
 
     key: "com.android.telephony.key",
@@ -14,7 +14,7 @@
 apex {
     name: "com.android.telephony",
     manifest: "apex_manifest.json",
-    apps: ["StkLib"],
+    //apps: ["StkLib"],
 
     defaults:["com.android.telephony-defaults"],
 }
diff --git a/res/drawable/preference_background.xml b/res/drawable/preference_background.xml
index 19ca432..1ec90fb 100644
--- a/res/drawable/preference_background.xml
+++ b/res/drawable/preference_background.xml
@@ -21,7 +21,7 @@
         android:insetBottom="0dip">
 
     <shape android:shape="rectangle">
-        <solid android:color="@*android:color/background_material_light" />
+        <solid android:color="@color/background_material_light" />
     </shape>
 
 </inset>
diff --git a/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml b/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml
deleted file mode 100644
index 905dc55..0000000
--- a/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- Variant of progress_indeterminate_horizontal_material in frameworks/base/core/res, which
-     draws the whole height of the progress bar instead having blank space above and below the
-     bar. -->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/vector_drawable_progress_indeterminate_horizontal_trimmed" >
-    <target
-        android:name="rect2_grp"
-        android:animation="@*android:anim/progress_indeterminate_horizontal_rect2" />
-    <target
-        android:name="rect1_grp"
-        android:animation="@*android:anim/progress_indeterminate_horizontal_rect1" />
-</animated-vector>
\ No newline at end of file
diff --git a/res/layout/choose_network_progress_header.xml b/res/layout/choose_network_progress_header.xml
deleted file mode 100644
index 671c297..0000000
--- a/res/layout/choose_network_progress_header.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-    Copyright (C) 2018 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-        http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-
-<FrameLayout
-    android:layout_width="match_parent"
-    android:layout_height="3dp"
-    xmlns:android="http://schemas.android.com/apk/res/android">
-    <View
-        android:id="@+id/progress_bar_background"
-        style="@style/TrimmedHorizontalProgressBar"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:background="?android:attr/colorSecondary" />
-    <ProgressBar
-        android:id="@+id/progress_bar_animation"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        style="@style/TrimmedHorizontalProgressBar"
-        android:indeterminate="true" />
-</FrameLayout>
\ No newline at end of file
diff --git a/res/layout/emergency_dialer.xml b/res/layout/emergency_dialer.xml
index d14a679..ab32c62 100644
--- a/res/layout/emergency_dialer.xml
+++ b/res/layout/emergency_dialer.xml
@@ -58,8 +58,6 @@
         android:accessibilityPaneTitle="@string/pane_title_emergency_dialpad"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:paddingLeft="36dp"
-        android:paddingRight="36dp"
         android:paddingBottom="@dimen/dialpad_bottom_padding"
         android:visibility="visible">
         <LinearLayout
@@ -73,6 +71,7 @@
                 android:id="@+id/emergency_action_group"
                 android:layout_height="64dp"
                 android:layout_width="match_parent"
+                android:layout_marginHorizontal="36dp"
                 android:layout_marginTop="16dp"
                 android:layout_marginBottom="24dp">
 
@@ -155,8 +154,14 @@
                 </FrameLayout>
 
             </com.android.phone.EmergencyActionGroup>
-
+            <Space
+                android:id="@+id/emergency_info_dialpad_spacer"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1"/>
             <include layout="@layout/dialpad_view_unthemed"
+                     android:layout_height="wrap_content"
+                     android:layout_width="match_parent"
                      android:theme="?attr/dialpadTheme" />
 
         </LinearLayout>
diff --git a/res/layout/pref_dialog_editpin.xml b/res/layout/pref_dialog_editpin.xml
deleted file mode 100644
index 94cdadf..0000000
--- a/res/layout/pref_dialog_editpin.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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.
--->
-
-<!-- Layout used as the dialog's content View for EditTextPreference. -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@*android:id/edittext_container"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:orientation="vertical"
-    android:padding="?android:attr/dialogPreferredPadding">
-
-    <TextView android:id="@android:id/message"
-        style="?android:attr/textAppearanceSmall"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:textColor="?android:attr/textColorSecondary" />
-
-</LinearLayout>
diff --git a/res/values-af/config.xml b/res/values-af/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-af/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-am/config.xml b/res/values-am/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-am/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ar/config.xml b/res/values-ar/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ar/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-as/config.xml b/res/values-as/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-as/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-az/config.xml b/res/values-az/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-az/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-b+sr+Latn/config.xml b/res/values-b+sr+Latn/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-b+sr+Latn/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-be/config.xml b/res/values-be/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-be/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-bg/config.xml b/res/values-bg/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-bg/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-bn/config.xml b/res/values-bn/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-bn/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-bs/config.xml b/res/values-bs/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-bs/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ca/config.xml b/res/values-ca/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ca/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-cs/config.xml b/res/values-cs/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-cs/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-da/config.xml b/res/values-da/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-da/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-de/config.xml b/res/values-de/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-de/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-el/config.xml b/res/values-el/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-el/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-en-rAU/config.xml b/res/values-en-rAU/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-en-rAU/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-en-rCA/config.xml b/res/values-en-rCA/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-en-rCA/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-en-rGB/config.xml b/res/values-en-rGB/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-en-rGB/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-en-rIN/config.xml b/res/values-en-rIN/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-en-rIN/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-en-rXC/config.xml b/res/values-en-rXC/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-en-rXC/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-es-rUS/config.xml b/res/values-es-rUS/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-es-rUS/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-es/config.xml b/res/values-es/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-es/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-et/config.xml b/res/values-et/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-et/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-eu/config.xml b/res/values-eu/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-eu/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-fa/config.xml b/res/values-fa/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-fa/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-fi/config.xml b/res/values-fi/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-fi/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-fr-rCA/config.xml b/res/values-fr-rCA/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-fr-rCA/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-fr/config.xml b/res/values-fr/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-fr/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-gl/config.xml b/res/values-gl/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-gl/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-gu/config.xml b/res/values-gu/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-gu/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-h500dp/dimens.xml b/res/values-h500dp/dimens.xml
index 2c7c797..d74f0a1 100644
--- a/res/values-h500dp/dimens.xml
+++ b/res/values-h500dp/dimens.xml
@@ -16,5 +16,5 @@
   -->
 
 <resources>
-    <dimen name="dialpad_bottom_padding">36dp</dimen>
+    <dimen name="dialpad_bottom_padding">16dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/res/values-hi/config.xml b/res/values-hi/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-hi/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-hr/config.xml b/res/values-hr/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-hr/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-hu/config.xml b/res/values-hu/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-hu/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-hy/config.xml b/res/values-hy/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-hy/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-in/config.xml b/res/values-in/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-in/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-is/config.xml b/res/values-is/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-is/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-it/config.xml b/res/values-it/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-it/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-iw/config.xml b/res/values-iw/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-iw/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ja/config.xml b/res/values-ja/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ja/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ka/config.xml b/res/values-ka/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ka/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-kk/config.xml b/res/values-kk/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-kk/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-km/config.xml b/res/values-km/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-km/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-kn/config.xml b/res/values-kn/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-kn/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ko/config.xml b/res/values-ko/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ko/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ky/config.xml b/res/values-ky/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ky/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-lo/config.xml b/res/values-lo/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-lo/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-lt/config.xml b/res/values-lt/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-lt/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-lv/config.xml b/res/values-lv/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-lv/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-mk/config.xml b/res/values-mk/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-mk/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ml/config.xml b/res/values-ml/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ml/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-mn/config.xml b/res/values-mn/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-mn/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-mr/config.xml b/res/values-mr/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-mr/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ms/config.xml b/res/values-ms/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ms/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-my/config.xml b/res/values-my/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-my/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-nb/config.xml b/res/values-nb/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-nb/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ne/config.xml b/res/values-ne/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ne/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-night/styles.xml b/res/values-night/styles.xml
index fa5c8a1..f7d831b 100644
--- a/res/values-night/styles.xml
+++ b/res/values-night/styles.xml
@@ -27,31 +27,31 @@
         <item name="android:dialogTheme">@style/DialerAlertDialogTheme</item>
     </style>
 
-    <style name="EmergencyInfoNameTextAppearance">
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+    <style name="EmergencyInfoNameTextAppearance"
+           parent="@android:style/TextAppearance.Material.Subhead">
         <item name="android:textColor">@android:color/white</item>
         <item name="android:textSize">@dimen/emergency_info_name_text_size</item>
     </style>
 
-    <style name="EmergencyInfoHintTextAppearance">
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+    <style name="EmergencyInfoHintTextAppearance"
+           parent="@android:style/TextAppearance.Material.Subhead">
         <item name="android:textColor">@color/white_70_percent</item>
         <item name="android:textSize">@dimen/emergency_info_hint_text_size</item>
     </style>
 
-    <style name="EmergencyInfoTapHintTextAppearance">
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+    <style name="EmergencyInfoTapHintTextAppearance"
+           parent="@android:style/TextAppearance.Material.Subhead">
         <item name="android:textColor">@android:color/white</item>
         <item name="android:textSize">@dimen/emergency_info_tap_hint_text_size</item>
     </style>
 
-    <style name="ShortcutViewHintTextAppearance">
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+    <style name="ShortcutViewHintTextAppearance"
+           parent="@android:style/TextAppearance.Material.Subhead">
         <item name="android:textColor">@android:color/white</item>
     </style>
 
-    <style name="PhoneNumberTextAppearance">
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+    <style name="PhoneNumberTextAppearance"
+           parent="@android:style/TextAppearance.Material.Subhead">
         <item name="android:textColor">@android:color/white</item>
         <item name="android:textSize">@dimen/emergency_shortcut_number_text_size</item>
     </style>
@@ -62,8 +62,8 @@
         <item name="android:textSize">@dimen/emergency_shortcut_type_text_size</item>
     </style>
 
-    <style name="PhoneNumberTapHintAppearance">
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+    <style name="PhoneNumberTapHintAppearance"
+           parent="@android:style/TextAppearance.Material.Subhead">
         <item name="android:textColor">@android:color/white</item>
         <item name="android:textSize">@dimen/emergency_shortcut_tap_hint_text_size</item>
     </style>
diff --git a/res/values-nl/config.xml b/res/values-nl/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-nl/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-or/config.xml b/res/values-or/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-or/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-pa/config.xml b/res/values-pa/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-pa/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-pl/config.xml b/res/values-pl/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-pl/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-pt-rPT/config.xml b/res/values-pt-rPT/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-pt-rPT/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-pt/config.xml b/res/values-pt/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-pt/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ro/config.xml b/res/values-ro/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ro/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ru/config.xml b/res/values-ru/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ru/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-si/config.xml b/res/values-si/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-si/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-sk/config.xml b/res/values-sk/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-sk/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-sl/config.xml b/res/values-sl/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-sl/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-sq/config.xml b/res/values-sq/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-sq/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-sr/config.xml b/res/values-sr/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-sr/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-sv/config.xml b/res/values-sv/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-sv/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-sw/config.xml b/res/values-sw/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-sw/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ta/config.xml b/res/values-ta/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ta/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-te/config.xml b/res/values-te/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-te/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-th/config.xml b/res/values-th/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-th/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-tl/config.xml b/res/values-tl/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-tl/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-tr/config.xml b/res/values-tr/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-tr/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-uk/config.xml b/res/values-uk/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-uk/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ur/config.xml b/res/values-ur/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ur/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-uz/config.xml b/res/values-uz/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-uz/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-vi/config.xml b/res/values-vi/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-vi/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-zh-rCN/config.xml b/res/values-zh-rCN/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-zh-rCN/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-zh-rHK/config.xml b/res/values-zh-rHK/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-zh-rHK/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-zh-rTW/config.xml b/res/values-zh-rTW/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-zh-rTW/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-zu/config.xml b/res/values-zu/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-zu/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2009 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.
- -->
-
-<!--  NOTE: Many variables that used to be in this file have been migrated to
-     CarrierConfigManager.java. Please consider whether new variables belong
-     there before adding to this file. Variables here should be more closely
-     related to devices than to networks.  -->
-
-<!--  Phone app resources that may need to be customized
-     for different hardware or product builds.  -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 8d84baf..fca8acf 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -15,21 +15,6 @@
 -->
 
 <resources>
-    <!-- Base attributes available to CheckBoxPreference. Copied from frameworks/base/core/res. -->
-    <declare-styleable name="CheckBoxPreference">
-        <!-- The summary for the Preference in a PreferenceActivity screen when the
-             CheckBoxPreference is checked. If separate on/off summaries are not
-             needed, the summary attribute can be used instead. -->
-        <attr name="android:summaryOn" />
-        <!-- The summary for the Preference in a PreferenceActivity screen when the
-             CheckBoxPreference is unchecked. If separate on/off summaries are not
-             needed, the summary attribute can be used instead. -->
-        <attr name="android:summaryOff" />
-        <!-- The state (true for on, or false for off) that causes dependents to be disabled. By default,
-             dependents will be disabled when this is unchecked, so the value of this preference is false. -->
-        <attr name="android:disableDependentsState" />
-    </declare-styleable>
-
     <declare-styleable name="EditPhoneNumberPreference">
         <!-- The enable button text. -->
         <attr name="enableButtonText" format="string" />
diff --git a/res/values/config.xml b/res/values/config.xml
index 8bc1919..d4e4c79 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -209,7 +209,7 @@
 
     <!-- The package to handle visual voicemail if the default dialer or the package
     CarrierConfigManager.KEY_CARRIER_VVM_PACKAGE_NAME_STRING does not handle it -->
-    <string name="system_visual_voicemail_client"></string>
+    <string name="system_visual_voicemail_client" translatable="false"/>
 
     <!-- Flag to enable VVM3 visual voicemail. VVM3 is used by Verizon Wireless. -->
     <bool name="vvm3_enabled">false</bool>
@@ -235,6 +235,12 @@
     <!-- Flag indicating whether the device supports RTT (real-time text) -->
     <bool name="config_support_rtt">false</bool>
 
+    <!-- String indicating the package name of the device ImsService implementation for MMTEL. -->
+    <string name="config_ims_mmtel_package" translatable="false"/>
+
+    <!-- String indicating the package name of the device ImsService implementation for RCS. -->
+    <string name="config_ims_rcs_package" translatable="false"/>
+
     <!-- The package name for the platform number verification supplier app. -->
     <string name="platform_number_verification_package" translatable="false"></string>
 
@@ -251,6 +257,14 @@
          audio stream which the remote party will be able to hear. -->
     <bool name="config_support_telephony_audio_device">false</bool>
 
+    <string-array translatable="false" name="config_volte_provision_error_on_publish_response">
+        <item>403 not authorized for presence</item>
+    </string-array>
+
+    <string-array translatable="false" name="config_rcs_provision_error_on_publish_response">
+        <item>404 not found</item>
+    </string-array>
+
     <!-- The country list that shortcut view can be enabled. -->
     <string-array name="config_countries_to_enable_shortcut_view" translatable="false">
     </string-array>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b97ef10..b74b2ff 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -273,6 +273,15 @@
     <string name="sum_cfnrc_disabled">Off</string>
     <!-- Error message displayed after failing to disable forwarding calls when the phone is unreachable -->
     <string name="disable_cfnrc_forbidden">Your carrier doesn\'t support disabling call forwarding when your phone is unreachable.</string>
+    <string name="registration_cf_forbidden">Your carrier doesn\'t support call forwarding.</string>
+
+    <!-- Cdma Call waiting settings screen, setting option name -->
+    <string name="cdma_call_waiting">Turn on call waiting?</string>
+    <string name="enable_cdma_call_waiting_setting">During a call, you\'ll be notified about incoming calls</string>
+    <string name="enable_cdma_cw">Turn on</string>
+    <string name="disable_cdma_cw">Cancel</string>
+    <string name="cdma_call_waiting_in_ims_on">CDMA Call Waiting under IMS On</string>
+    <string name="cdma_call_waiting_in_ims_off">CDMA Call Waiting under IMS Off</string>
 
     <!-- Title of the progress dialog displayed while updating Call settings -->
     <string name="updating_title">Call settings</string>
@@ -438,6 +447,17 @@
         <item>LTE/TDSCDMA/GSM/WCDMA</item>
         <item>TDSCDMA/CDMA/EVDO/GSM/WCDMA </item>
         <item>LTE/TDSCDMA/CDMA/EVDO/GSM/WCDMA</item>
+        <item>NR only</item>
+        <item>NR/LTE</item>
+        <item>NR/LTE/CDMA/EvDo</item>
+        <item>NR/LTE/GSM/WCDMA</item>
+        <item>NR/LTE/CDMA/EvDo/GSM/WCDMA</item>
+        <item>NR/LTE/WCDMA</item>
+        <item>NR/LTE/TDSCDMA</item>
+        <item>NR/LTE/TDSCDMA/GSM</item>
+        <item>NR/LTE/TDSCDMA/WCDMA</item>
+        <item>NR/LTE/TDSCDMA/GSM/WCDMA</item>
+        <item>NR/LTE/TDSCDMA/CDMA/EvDo/GSM/WCDMA</item>
     </string-array>
     <!-- The preferred network modes RIL constants, in order of the modes above,
          e.g. the choice "GSM/WCDMA preferred" has the corresponding value "0" -->
@@ -465,6 +485,17 @@
         <item>"20"</item>
         <item>"21"</item>
         <item>"22"</item>
+        <item>"23"</item>
+        <item>"24"</item>
+        <item>"25"</item>
+        <item>"26"</item>
+        <item>"27"</item>
+        <item>"28"</item>
+        <item>"29"</item>
+        <item>"30"</item>
+        <item>"31"</item>
+        <item>"32"</item>
+        <item>"33"</item>
     </string-array>
 
     <!-- The following strings are summaries for preferred network modes in Mobile network settings,
@@ -493,6 +524,8 @@
     <string name="preferred_network_mode_lte_gsm_wcdma_summary">Preferred network mode: GSM/WCDMA/LTE</string>
     <!-- CDMA+LTE/EVDO -->
     <string name="preferred_network_mode_lte_cdma_evdo_summary">Preferred network mode: CDMA+LTE/EVDO</string>
+    <!-- LTE/CDMA/EvDo/GSM/WCDMA [CHAR LIMIT=NONE] -->
+    <string name="preferred_network_mode_lte_cdma_evdo_gsm_wcdma_summary">Preferred network mode: LTE/CDMA/EvDo/GSM/WCDMA</string>
     <!-- Global -->
     <string name="preferred_network_mode_global_summary">Preferred network mode: Global</string>
     <!-- LTE / WCDMA -->
@@ -521,6 +554,28 @@
     <string name="preferred_network_mode_tdscdma_cdma_evdo_gsm_wcdma_summary">Preferred network mode: TDSCDMA/CDMA/EvDo/GSM/WCDMA</string>
     <!-- LTE/TDSCDMA/CDMA/EvDo/GSM/WCDMA -->
     <string name="preferred_network_mode_lte_tdscdma_cdma_evdo_gsm_wcdma_summary">Preferred network mode: LTE/TDSCDMA/CDMA/EvDo/GSM/WCDMA</string>
+    <!-- NR only [CHAR LIMIT=NONE] -->
+    <string name="preferred_network_mode_nr_only_summary">Preferred network mode: NR only</string>
+    <!-- NR / LTE [CHAR LIMIT=NONE] -->
+    <string name="preferred_network_mode_nr_lte_summary">Preferred network mode: NR / LTE</string>
+    <!-- NR/LTE/CDMA/EvDo [CHAR LIMIT=NONE] -->
+    <string name="preferred_network_mode_nr_lte_cdma_evdo_summary">Preferred network mode: NR/LTE/CDMA/EvDo</string>
+    <!-- NR/LTE/GSM/WCDMA [CHAR LIMIT=NONE] -->
+    <string name="preferred_network_mode_nr_lte_gsm_wcdma_summary">Preferred network mode: NR/LTE/GSM/WCDMA</string>
+    <!-- NR/LTE/TDSCDMA/CDMA/EvDo/GSM/WCDMA [CHAR LIMIT=NONE] -->
+    <string name="preferred_network_mode_nr_lte_cdma_evdo_gsm_wcdma_summary">Preferred network mode: NR/LTE/CDMA/EvDo/GSM/WCDMA</string>
+    <!-- NR/LTE/WCDMA [CHAR LIMIT=NONE] -->
+    <string name="preferred_network_mode_nr_lte_wcdma_summary">Preferred network mode: NR/LTE/WCDMA</string>
+    <!-- NR/LTE/TDSCDMA [CHAR LIMIT=NONE] -->
+    <string name="preferred_network_mode_nr_lte_tdscdma_summary">Preferred network mode: NR/LTE/TDSCDMA</string>
+    <!-- NR/LTE/TDSCDMA/GSM [CHAR LIMIT=NONE] -->
+    <string name="preferred_network_mode_nr_lte_tdscdma_gsm_summary">Preferred network mode: NR/LTE/TDSCDMA/GSM</string>
+    <!-- NR/LTE/TDSCDMA/WCDMA [CHAR LIMIT=NONE] -->
+    <string name="preferred_network_mode_nr_lte_tdscdma_wcdma_summary">Preferred network mode: NR/LTE/TDSCDMA/WCDMA</string>
+    <!-- NR/LTE/TDSCDMA/GSM/WCDMA [CHAR LIMIT=NONE] -->
+    <string name="preferred_network_mode_nr_lte_tdscdma_gsm_wcdma_summary">Preferred network mode: NR/LTE/TDSCDMA/GSM/WCDMA</string>
+    <!-- NR/LTE/TDSCDMA/CDMA/EvDo/GSM/WCDMA [CHAR LIMIT=NONE] -->
+    <string name="preferred_network_mode_nr_lte_tdscdma_cdma_evdo_gsm_wcdma_summary">Preferred network mode: NR/LTE/TDSCDMA/CDMA/EvDo/GSM/WCDMA</string>
 
     <!-- Mobile network settings screen, name for call settings category -->
     <string name="call_category">Calling</string>
@@ -757,6 +812,10 @@
     <string name="multi_category_enable">Multi-category enabled</string>
     <string name="multi_category_disable">Multi-category disabled</string>
 
+    <string name="network_recommended">\u0020(recommended)</string>
+    <string name="network_5G" translatable="false">5G</string>
+    <string name="network_lte_pure" translatable="false">LTE</string>
+    <string name="network_4G_pure" translatable="false">4G</string>
     <string name="network_lte">LTE (recommended)</string>
     <string name="network_4G">4G (recommended)</string>
     <string name="network_3G" translatable="false">3G</string>
@@ -1397,6 +1456,17 @@
     <string name="alert_dialog_no">No</string>
     <!-- ECM: ECM exit dialog choice -->
     <string name="alert_dialog_dismiss">Dismiss</string>
+    <!-- ECM: Notification body wihout data restriction hint -->
+    <string name="phone_in_ecm_call_notification_text_without_data_restriction_hint">The phone is in emergency callback mode</string>
+    <!-- ECM: Displays the time when ECM will end without data restriction hint, Example: "Until 10:45 AM" -->
+    <string name="phone_in_ecm_notification_complete_time_without_data_restriction_hint">Until <xliff:g id="completeTime">%s</xliff:g></string>
+    <!-- ECM: Dialog box message without data restriction hint for exiting from the notifications screen -->
+    <plurals name="alert_dialog_exit_ecm_without_data_restriction_hint">
+        <!-- number of minutes is one -->
+        <item quantity="one">The phone will be in emergency callback mode for <xliff:g id="count">%s</xliff:g> minute.\nDo you want to exit now?</item>
+        <!-- number of minutes is not equal to one -->
+        <item quantity="other">The phone will be in emergency callback mode for <xliff:g id="count">%s</xliff:g> minutes.\nDo you want to exit now?</item>
+    </plurals>
 
     <!-- For incoming calls, this is a string we can get from a CDMA network instead of
          the actual phone number, to indicate there's no number present.  DO NOT TRANSLATE. -->
@@ -1793,8 +1863,6 @@
     <string name="messageCallBarring">Enter password</string>
     <!-- Call barring settings screen, section heading -->
     <string name="call_barring_settings">Call barring settings</string>
-    <!-- Call barring settings screen, deactivate all call barring settings -->
-    <string name="call_barring_deactivate_all_no_password">Deactivate all call barring settings?</string>
     <!-- In-call screen: error message shown when the user attempts to place a call, but the network
          does not have enough resources (e.g. it is busy) and the call cannot be placed. -->
     <string name="callFailed_NetworkBusy">Network is busy.  Please try your call again later.</string>
@@ -2094,5 +2162,4 @@
     <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 e95142b..e8a0bed 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -211,12 +211,6 @@
         <item name="android:textColor">?android:attr/textColorPrimaryInverseDisableOnly</item>
     </style>
 
-    <style name="TrimmedHorizontalProgressBar" parent="android:Widget.Material.ProgressBar.Horizontal">
-        <item name="android:indeterminateDrawable">@drawable/progress_indeterminate_horizontal_material_trimmed</item>
-        <item name="android:minHeight">3dip</item>
-        <item name="android:maxHeight">3dip</item>
-    </style>
-
     <style name="Empty" parent="@android:style/Theme.Material.Light">
         <item name="android:forceDarkAllowed">true</item>
         <item name="android:windowIsTranslucent">true</item>
@@ -227,33 +221,6 @@
         <item name="android:backgroundDimEnabled">true</item>
     </style>
 
-    <style name="InCallAnimationStyle" parent="@*android:style/Animation.Holo.Activity">
-        <!-- Suppress task-to-task animation happening during the transition from
-             OutgoingCallBroadcaster (and SipOptionHandler) to InCallScreen.
-             The transition unexpectedly happens during the transition (inside the phone task),
-             because InCallScreen is using android:launchMode="singleInstance".
-
-             - taskOpenEnterAnimation/taskOpenExitAnimation is used for the first time
-               InCallScreen instance is created.
-
-             - taskToFrontEnterAnimation/taskToFrontExitAnimation is used when InCallScreen
-               is already available.
-               (Note that InCallScreen won't be destroyed once it is created)
-
-             TODO: try removing the flag instead -->
-        <item name="*android:taskOpenEnterAnimation">@*android:anim/activity_open_enter</item>
-        <item name="*android:taskOpenExitAnimation">@*android:anim/activity_open_exit</item>
-        <item name="*android:taskToFrontEnterAnimation">@*android:anim/activity_open_enter</item>
-        <item name="*android:taskToFrontExitAnimation">@*android:anim/activity_open_exit</item>
-    </style>
-
-    <style name="OutgoingAnimationStyle" parent="@*android:style/Animation.Holo.Activity">
-        <!-- Suppress task-to-task transition animation happening from
-             DialtactsActivity to OutgoingCallBroadcaster. -->
-        <item name="*android:taskOpenEnterAnimation">@*android:anim/activity_open_enter</item>
-        <item name="*android:taskOpenExitAnimation">@*android:anim/activity_open_exit</item>
-    </style>
-
     <!-- Style for the call settings action bar.  Should be kept in sync with Dialer. -->
     <style name="DialtactsActionBarStyle" parent="@style/TelephonyActionBarStyle">
         <!-- Shift the title text to the right -->
@@ -284,7 +251,7 @@
         <item name="android:src">@drawable/overflow_menu</item>
     </style>
 
-    <style name="EmergencyDialerTheme" parent="@*android:style/Theme.DeviceDefault.Settings.Dark.NoActionBar">
+    <style name="EmergencyDialerTheme" parent="@android:style/Theme.Material.NoActionBar">
         <item name="android:forceDarkAllowed">true</item>
         <item name="android:colorPrimaryDark">?android:attr/colorPrimary</item>
         <item name="android:colorBackgroundCacheHint">@null</item>
@@ -293,7 +260,7 @@
         <item name="android:navigationBarColor">@android:color/transparent</item>
         <item name="android:homeAsUpIndicator">@drawable/ic_back_arrow</item>
         <item name="emergencyButtonBackgroundColor">#3cffffff</item>
-        <item name="dialpadTheme">@style/Dialpad_DarkTransparent</item>
+        <item name="dialpadTheme">@style/Dialpad_DarkTransparent.Emergency</item>
     </style>
 
     <style name="EmergencyDialerThemeDark" parent="@style/EmergencyDialerTheme">
@@ -301,7 +268,15 @@
         <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
         <item name="emergencyButtonBackgroundColor">#19414549</item>
         <item name="android:colorControlHighlight">#40000000</item>
-        <item name="dialpadTheme">@style/Dialpad_LightTransparent</item>
+        <item name="dialpadTheme">@style/Dialpad_LightTransparent.Emergency</item>
+    </style>
+
+    <style name="Dialpad_LightTransparent.Emergency">
+        <item name="dialpad_delete_padding">16dp</item>
+    </style>
+
+    <style name="Dialpad_DarkTransparent.Emergency">
+        <item name="dialpad_delete_padding">16dp</item>
     </style>
 
     <style name="EmergencyDialerAlertDialogTheme"
@@ -318,13 +293,6 @@
         <item name="android:actionOverflowButtonStyle">@style/DialtactsActionBarOverflow</item>
     </style>
 
-    <style name="OutgoingCallBroadcasterTheme" parent="@android:style/Theme.Holo.NoActionBar">
-        <item name="android:forceDarkAllowed">true</item>
-        <item name="android:windowBackground">@android:color/black</item>
-
-        <item name="*android:windowAnimationStyle">@style/OutgoingAnimationStyle</item>
-    </style>
-
     <style name="DialtactsDigitsTextAppearance">
         <item name="android:maxLines">1</item>
         <item name="android:textSize">@dimen/dialpad_digits_text_size</item>
@@ -343,48 +311,47 @@
         <item name="android:backgroundDimEnabled">false</item>
     </style>
 
-    <style name="CallSettingsWithoutDividerTheme" parent="SettingsLight">
-        <item name="android:forceDarkAllowed">true</item>
+    <style name="CallSettingsWithoutDividerTheme" parent="DialerSettingsLight">
         <item name="android:listDivider">@null</item>
     </style>
 
-    <style name="EmergencyInfoNameTextAppearance">
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
-        <item name="android:textColor">@*android:color/primary_text_default_material_dark</item>
+    <style name="EmergencyInfoNameTextAppearance"
+           parent="@android:style/TextAppearance.Material.Subhead">
+        <item name="android:textColor">@color/primary_text_default_material_dark</item>
         <item name="android:textSize">@dimen/emergency_info_name_text_size</item>
     </style>
 
-    <style name="EmergencyInfoHintTextAppearance">
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
-        <item name="android:textColor">@*android:color/secondary_text_default_material_dark</item>
+    <style name="EmergencyInfoHintTextAppearance"
+           parent="@android:style/TextAppearance.Material.Subhead">
+        <item name="android:textColor">@color/secondary_text_default_material_dark</item>
         <item name="android:textSize">@dimen/emergency_info_hint_text_size</item>
     </style>
 
-    <style name="EmergencyInfoTapHintTextAppearance">
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+    <style name="EmergencyInfoTapHintTextAppearance"
+           parent="@android:style/TextAppearance.Material.Subhead">
         <item name="android:textColor">@android:color/white</item>
         <item name="android:textSize">@dimen/emergency_info_tap_hint_text_size</item>
     </style>
 
-    <style name="ShortcutViewHintTextAppearance">
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
-        <item name="android:textColor">@*android:color/secondary_text_default_material_dark</item>
+    <style name="ShortcutViewHintTextAppearance"
+           parent="@android:style/TextAppearance.Material.Subhead">
+        <item name="android:textColor">@color/secondary_text_default_material_dark</item>
     </style>
 
-    <style name="PhoneNumberTextAppearance">
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
-        <item name="android:textColor">@*android:color/primary_text_default_material_light</item>
+    <style name="PhoneNumberTextAppearance"
+           parent="@android:style/TextAppearance.Material.Subhead">
+        <item name="android:textColor">@color/primary_text_default_material_light</item>
         <item name="android:textSize">@dimen/emergency_shortcut_number_text_size</item>
     </style>
 
     <style name="PhoneNumberTypeAppearance">
         <item name="android:fontFamily">roboto</item>
-        <item name="android:textColor">@*android:color/secondary_text_default_material_light</item>
+        <item name="android:textColor">@color/secondary_text_default_material_light</item>
         <item name="android:textSize">@dimen/emergency_shortcut_type_text_size</item>
     </style>
 
-    <style name="PhoneNumberTapHintAppearance">
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+    <style name="PhoneNumberTapHintAppearance"
+           parent="@android:style/TextAppearance.Material.Subhead">
         <item name="android:textColor">@android:color/white</item>
         <item name="android:textSize">@dimen/emergency_shortcut_tap_hint_text_size</item>
     </style>
diff --git a/res/values/styles_preference.xml b/res/values/styles_preference.xml
index fef4f72..eace2e7 100644
--- a/res/values/styles_preference.xml
+++ b/res/values/styles_preference.xml
@@ -19,22 +19,22 @@
 <!-- Things unrelated to preference framework UI customization should go to other styles files -->
 <resources>
     <!-- Preferences -->
-    <style name="SettingsPreference" parent="@*android:style/Preference.DeviceDefault">
+    <style name="SettingsPreference" parent="@style/Preference.Material">
         <item name="android:singleLineTitle">false</item>
         <item name="android:iconSpaceReserved">true</item>
     </style>
 
-    <style name="SettingsSwitchPreference" parent="@*android:style/Preference.DeviceDefault.SwitchPreference">
+    <style name="SettingsSwitchPreference" parent="@style/Preference.SwitchPreference.Material">
         <item name="android:iconSpaceReserved">true</item>
         <item name="android:singleLineTitle">false</item>
     </style>
 
-    <style name="SettingsDialogPreference" parent="@*android:style/Preference.DeviceDefault.DialogPreference">
+    <style name="SettingsDialogPreference" parent="@style/Preference.DialogPreference.Material">
         <item name="android:singleLineTitle">false</item>
         <item name="android:iconSpaceReserved">true</item>
     </style>
 
-    <style name="SettingsPreferenceScreen" parent="@*android:style/Preference.DeviceDefault.PreferenceScreen">
+    <style name="SettingsPreferenceScreen" parent="@style/Preference.PreferenceScreen.Material">
         <item name="android:singleLineTitle">false</item>
         <item name="android:iconSpaceReserved">true</item>
     </style>
diff --git a/res/xml/cdma_call_privacy.xml b/res/xml/cdma_call_privacy.xml
index 1aeeefe..a16a504 100644
--- a/res/xml/cdma_call_privacy.xml
+++ b/res/xml/cdma_call_privacy.xml
@@ -7,4 +7,14 @@
         android:title="@string/voice_privacy"
         android:persistent="false"
         android:summary="@string/voice_privacy_summary"/>
+
+    <PreferenceScreen
+        android:key="call_forwarding_key"
+        android:title="@string/labelCF"
+        android:persistent="false" />
+
+    <com.android.phone.CdmaCallWaitingPreference
+        android:key="call_waiting_key"
+        android:title="@string/labelCW"
+        android:persistent="false" />
 </PreferenceScreen>
diff --git a/sip/src/com/android/services/telephony/sip/SipIncomingCallReceiver.java b/sip/src/com/android/services/telephony/sip/SipIncomingCallReceiver.java
index 3212c00..2dbd707 100644
--- a/sip/src/com/android/services/telephony/sip/SipIncomingCallReceiver.java
+++ b/sip/src/com/android/services/telephony/sip/SipIncomingCallReceiver.java
@@ -84,7 +84,7 @@
     }
 
     private boolean isRunningInSystemUser() {
-        return UserHandle.myUserId() == UserHandle.USER_SYSTEM;
+        return UserHandle.myUserId() == UserHandle.SYSTEM.getIdentifier();
     }
 
     private static void log(String msg) {
diff --git a/sip/src/com/android/services/telephony/sip/SipSettings.java b/sip/src/com/android/services/telephony/sip/SipSettings.java
index ded16df..813ba51 100644
--- a/sip/src/com/android/services/telephony/sip/SipSettings.java
+++ b/sip/src/com/android/services/telephony/sip/SipSettings.java
@@ -42,6 +42,7 @@
 import com.android.phone.R;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.LinkedHashMap;
@@ -238,9 +239,9 @@
     }
 
     private void processActiveProfilesFromSipService() {
-        SipProfile[] activeList = {};
+        List<SipProfile> activeList = new ArrayList<>();
         try {
-            activeList = mSipManager.getListOfProfiles();
+            activeList = mSipManager.getProfiles();
         } catch (SipException e) {
             log("SipManager could not retrieve SIP profiles: " + e);
         }
diff --git a/sip/src/com/android/services/telephony/sip/SipUtil.java b/sip/src/com/android/services/telephony/sip/SipUtil.java
index ff38754..828174e 100644
--- a/sip/src/com/android/services/telephony/sip/SipUtil.java
+++ b/sip/src/com/android/services/telephony/sip/SipUtil.java
@@ -29,12 +29,11 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.phone.PhoneGlobals;
-import com.android.phone.R;
-import com.android.server.sip.SipService;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -46,6 +45,7 @@
             "com.android.services.telephony.sip.incoming_call_intent";
     static final String EXTRA_PHONE_ACCOUNT =
             "com.android.services.telephony.sip.phone_account";
+    static final String PHONE_PACKAGE = "com.android.phone";
 
     private SipUtil() {
     }
@@ -53,9 +53,9 @@
     public static boolean isVoipSupported(Context context) {
         return SipManager.isVoipSupported(context) &&
                 context.getResources().getBoolean(
-                        com.android.internal.R.bool.config_built_in_sip_phone) &&
-                context.getResources().getBoolean(
-                        com.android.internal.R.bool.config_voice_capable);
+                        com.android.internal.R.bool.config_built_in_sip_phone)
+                && ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE))
+                        .isVoiceCapable();
     }
 
     static PendingIntent createIncomingCallPendingIntent(
@@ -190,7 +190,10 @@
         // Migrate SIP database from DE->CE storage if the device has just upgraded.
         possiblyMigrateSipDb(phoneGlobalsContext);
         // Wait until boot complete to start SIP so that it has access to CE storage.
-        SipService.start(phoneGlobalsContext);
+        Intent startSipIntent = new Intent();
+        startSipIntent.setAction(SipManager.ACTION_START_SIP);
+        startSipIntent.setPackage(PHONE_PACKAGE);
+        phoneGlobalsContext.startService(startSipIntent);
     }
 
     /**
diff --git a/sip/src/com/android/services/telephony/sip/components/TelephonySipService.java b/sip/src/com/android/services/telephony/sip/components/TelephonySipService.java
new file mode 100644
index 0000000..5b863b1
--- /dev/null
+++ b/sip/src/com/android/services/telephony/sip/components/TelephonySipService.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 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.sip.components;
+
+import android.app.Service;
+import android.content.Intent;
+import android.net.sip.SipManager;
+import android.os.IBinder;
+
+import com.android.server.sip.SipService;
+
+/**
+ * This class represents telephony SIP service which handle start SIP service requests from
+ * Telephony.
+ */
+public class TelephonySipService extends Service {
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        if ((intent != null)
+                && SipManager.ACTION_START_SIP.equals(intent.getAction())) {
+            SipService.start(this);
+        }
+        return START_STICKY;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+}
diff --git a/src/com/android/phone/CallBarringDeselectAllPreference.java b/src/com/android/phone/CallBarringDeselectAllPreference.java
index e9310f8..7191937 100644
--- a/src/com/android/phone/CallBarringDeselectAllPreference.java
+++ b/src/com/android/phone/CallBarringDeselectAllPreference.java
@@ -19,12 +19,9 @@
 import android.content.Context;
 import android.os.Bundle;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.View;
 import android.widget.EditText;
 
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.phone.settings.fdn.EditPinPreference;
 
 /**
@@ -34,9 +31,6 @@
     private static final String LOG_TAG = "CallBarringDeselectAllPreference";
     private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
-    private boolean mShowPassword;
-    private Phone mPhone;
-
     /**
      * CallBarringDeselectAllPreference constructor.
      *
@@ -49,28 +43,10 @@
 
     @Override
     protected void showDialog(Bundle state) {
-        // Finds out if the password field should be shown or not.
-        ImsPhone imsPhone = mPhone != null ? (ImsPhone) mPhone.getImsPhone() : null;
-        mShowPassword = !(imsPhone != null && imsPhone.isUtEnabled());
-
-        // Selects dialog message depending on if the password field is shown or not.
-        setDialogMessage(getContext().getString(mShowPassword
-                ? R.string.messageCallBarring : R.string.call_barring_deactivate_all_no_password));
-
-        if (DBG) {
-            Log.d(LOG_TAG, "showDialog: mShowPassword: " + mShowPassword);
-        }
-
+        setDialogMessage(getContext().getString(R.string.messageCallBarring));
         super.showDialog(state);
     }
 
-    void init(Phone phone) {
-        if (DBG) {
-            Log.d(LOG_TAG, "init: phoneId = " + phone.getPhoneId());
-        }
-        mPhone = phone;
-    }
-
     @Override
     protected void onBindDialogView(View view) {
         super.onBindDialogView(view);
@@ -78,20 +54,7 @@
         final EditText editText = (EditText) view.findViewById(android.R.id.edit);
         if (editText != null) {
             // Hide the input-text-line if the password is not shown.
-            editText.setVisibility(mShowPassword ? View.VISIBLE : View.GONE);
+            editText.setVisibility(View.VISIBLE);
         }
     }
-
-    @Override
-    protected boolean needInputMethod() {
-        // Input method should only be displayed if the password-field is shown.
-        return mShowPassword;
-    }
-
-    /**
-     * Returns whether the password field is shown.
-     */
-    boolean isPasswordShown() {
-        return mShowPassword;
-    }
 }
diff --git a/src/com/android/phone/CallBarringEditPreference.java b/src/com/android/phone/CallBarringEditPreference.java
index edff1e3..5d83de1 100644
--- a/src/com/android/phone/CallBarringEditPreference.java
+++ b/src/com/android/phone/CallBarringEditPreference.java
@@ -35,10 +35,10 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
+import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
-import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.phone.settings.fdn.EditPinPreference;
 
 import java.lang.ref.WeakReference;
@@ -57,10 +57,7 @@
     private CharSequence mDisableText;
     private CharSequence mSummaryOn;
     private CharSequence mSummaryOff;
-    private CharSequence mDialogMessageEnabled;
-    private CharSequence mDialogMessageDisabled;
     private int mButtonClicked;
-    private boolean mShowPassword;
     private final MyHandler mHandler = new MyHandler(this);
     private Phone mPhone;
     private TimeConsumingPreferenceListener mTcpListener;
@@ -77,9 +74,9 @@
         super(context, attrs);
         // Get the summary settings, use CheckBoxPreference as the standard.
         TypedArray typedArray = context.obtainStyledAttributes(attrs,
-                android.R.styleable.CheckBoxPreference, 0, 0);
-        mSummaryOn = typedArray.getString(android.R.styleable.CheckBoxPreference_summaryOn);
-        mSummaryOff = typedArray.getString(android.R.styleable.CheckBoxPreference_summaryOff);
+                R.styleable.CheckBoxPreference, 0, 0);
+        mSummaryOn = typedArray.getString(R.styleable.CheckBoxPreference_summaryOn);
+        mSummaryOff = typedArray.getString(R.styleable.CheckBoxPreference_summaryOff);
         mDisableText = context.getText(R.string.disable);
         mEnableText = context.getText(R.string.enable);
         typedArray.recycle();
@@ -90,10 +87,6 @@
         typedArray = context.obtainStyledAttributes(attrs,
                 R.styleable.CallBarringEditPreference, 0, R.style.EditPhoneNumberPreference);
         mFacility = typedArray.getString(R.styleable.CallBarringEditPreference_facility);
-        mDialogMessageEnabled = typedArray.getString(
-                R.styleable.CallBarringEditPreference_dialogMessageEnabledNoPwd);
-        mDialogMessageDisabled = typedArray.getString(
-                R.styleable.CallBarringEditPreference_dialogMessageDisabledNoPwd);
         typedArray.recycle();
     }
 
@@ -116,7 +109,7 @@
         if (!skipReading) {
             // Query call barring status
             mPhone.getCallBarring(mFacility, "", mHandler.obtainMessage(
-                    MyHandler.MESSAGE_GET_CALL_BARRING), 0);
+                    MyHandler.MESSAGE_GET_CALL_BARRING), CommandsInterface.SERVICE_CLASS_VOICE);
             if (mTcpListener != null) {
                 mTcpListener.onStarted(this, true);
             }
@@ -130,29 +123,8 @@
     }
 
     @Override
-    protected boolean needInputMethod() {
-        // Input method should only be displayed if the password-field is shown.
-        return mShowPassword;
-    }
-
-    void setInputMethodNeeded(boolean needed) {
-        mShowPassword = needed;
-    }
-
-    @Override
     protected void showDialog(Bundle state) {
-        setShowPassword();
-        if (mShowPassword) {
-            setDialogMessage(getContext().getString(R.string.messageCallBarring));
-        } else {
-            setDialogMessage(mIsActivated ? mDialogMessageEnabled : mDialogMessageDisabled);
-        }
-
-        if (DBG) {
-            Log.d(LOG_TAG, "showDialog: mShowPassword: " + mShowPassword
-                    + ", mIsActivated: " + mIsActivated);
-        }
-
+        setDialogMessage(getContext().getString(R.string.messageCallBarring));
         super.showDialog(state);
     }
 
@@ -204,8 +176,7 @@
             editText.setTransformationMethod(PasswordTransformationMethod.getInstance());
             editText.setKeyListener(DigitsKeyListener.getInstance());
 
-            // Hide the input-text-line if the password is not shown.
-            editText.setVisibility(mShowPassword ? View.VISIBLE : View.GONE);
+            editText.setVisibility(View.VISIBLE);
         }
     }
 
@@ -217,17 +188,14 @@
                     + positiveResult);
         }
         if (mButtonClicked != DialogInterface.BUTTON_NEGATIVE) {
-            String password = null;
-            if (mShowPassword) {
-                password = getEditText().getText().toString();
+            String password = getEditText().getText().toString();
 
-                // Check if the password is valid.
-                if (password == null || password.length() != PW_LENGTH) {
-                    Toast.makeText(getContext(),
-                            getContext().getString(R.string.call_barring_right_pwd_number),
-                            Toast.LENGTH_SHORT).show();
-                    return;
-                }
+            // Check if the password is valid.
+            if (password == null || password.length() != PW_LENGTH) {
+                Toast.makeText(getContext(),
+                        getContext().getString(R.string.call_barring_right_pwd_number),
+                        Toast.LENGTH_SHORT).show();
+                return;
             }
 
             if (DBG) {
@@ -235,7 +203,8 @@
             }
             // Send set call barring message to RIL layer.
             mPhone.setCallBarring(mFacility, !mIsActivated, password,
-                    mHandler.obtainMessage(MyHandler.MESSAGE_SET_CALL_BARRING), 0);
+                    mHandler.obtainMessage(MyHandler.MESSAGE_SET_CALL_BARRING),
+                    CommandsInterface.SERVICE_CLASS_VOICE);
             if (mTcpListener != null) {
                 mTcpListener.onStarted(this, false);
             }
@@ -254,11 +223,6 @@
         notifyDependencyChange(shouldDisableDependents());
     }
 
-    private void setShowPassword() {
-        ImsPhone imsPhone = mPhone != null ? (ImsPhone) mPhone.getImsPhone() : null;
-        mShowPassword = !(imsPhone != null && imsPhone.isUtEnabled());
-    }
-
     @Override
     public boolean shouldDisableDependents() {
         return mIsActivated;
@@ -310,16 +274,6 @@
                 pref.mTcpListener.onFinished(pref, false);
             } else {
                 pref.mTcpListener.onFinished(pref, true);
-                ImsPhone imsPhone = pref.mPhone != null
-                        ? (ImsPhone) pref.mPhone.getImsPhone() : null;
-                if (!pref.mShowPassword && (imsPhone == null || !imsPhone.isUtEnabled())) {
-                    // Re-enable password when rejected from NW and modem would perform CSFB
-                    pref.mShowPassword = true;
-                    if (DBG) {
-                        Log.d(LOG_TAG,
-                                "handleGetCallBarringResponse: mShowPassword changed for CSFB");
-                    }
-                }
             }
 
             // Unsuccessful query for call barring.
@@ -374,7 +328,7 @@
                     "",
                     obtainMessage(MESSAGE_GET_CALL_BARRING, 0, MESSAGE_SET_CALL_BARRING,
                             ar.exception),
-                    0);
+                    CommandsInterface.SERVICE_CLASS_VOICE);
         }
     }
 }
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index 3f57cae..9faffa1 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -396,11 +396,7 @@
             } else {
                 if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
                     prefSet.removePreference(fdnButton);
-
-                    if (!carrierConfig.getBoolean(
-                            CarrierConfigManager.KEY_VOICE_PRIVACY_DISABLE_UI_BOOL)) {
-                        addPreferencesFromResource(R.xml.cdma_call_privacy);
-                    }
+                    addPreferencesFromResource(R.xml.cdma_call_privacy);
                 } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
                     if (mPhone.getIccCard() == null || !mPhone.getIccCard().getIccFdnAvailable()) {
                         prefSet.removePreference(fdnButton);
diff --git a/src/com/android/phone/CallForwardEditPreference.java b/src/com/android/phone/CallForwardEditPreference.java
index 76f17b1..8e0b685 100644
--- a/src/com/android/phone/CallForwardEditPreference.java
+++ b/src/com/android/phone/CallForwardEditPreference.java
@@ -122,7 +122,27 @@
         Log.d(LOG_TAG, "mButtonClicked=" + mButtonClicked + ", positiveResult=" + positiveResult);
         // Ignore this event if the user clicked the cancel button, or if the dialog is dismissed
         // without any button being pressed (back button press or click event outside the dialog).
-        if (this.mButtonClicked != DialogInterface.BUTTON_NEGATIVE) {
+        if (isUnknownStatus() && this.mButtonClicked != DialogInterface.BUTTON_NEGATIVE) {
+            int action = (mButtonClicked == DialogInterface.BUTTON_POSITIVE) ?
+                CommandsInterface.CF_ACTION_REGISTRATION :
+                CommandsInterface.CF_ACTION_DISABLE;
+            final String number = (action == CommandsInterface.CF_ACTION_DISABLE) ?
+                    "" : getPhoneNumber();
+
+            Log.d(LOG_TAG, "reason=" + reason + ", action=" + action + ", number=" + number);
+
+            // Display no forwarding number while we're waiting for confirmation.
+            setSummaryOff("");
+
+            mPhone.setCallForwardingOption(action,
+                    reason,
+                    number,
+                    mServiceClass,
+                    0,
+                    mHandler.obtainMessage(MyHandler.MESSAGE_SET_CF,
+                        action,
+                        MyHandler.MESSAGE_SET_CF));
+        } else if (this.mButtonClicked != DialogInterface.BUTTON_NEGATIVE) {
             int action = (isToggled() || (mButtonClicked == DialogInterface.BUTTON_POSITIVE)) ?
                     CommandsInterface.CF_ACTION_REGISTRATION :
                     CommandsInterface.CF_ACTION_DISABLE;
@@ -159,6 +179,7 @@
                     mPhone.setCallForwardingOption(action,
                             reason,
                             number,
+                            mServiceClass,
                             time,
                             mHandler.obtainMessage(MyHandler.MESSAGE_SET_CF,
                                     action,
@@ -193,6 +214,7 @@
             Log.i(LOG_TAG, "handleGetCFResponse: Overridding CF number");
         }
 
+        setUnknownStatus(callForwardInfo.status == CommandsInterface.SS_STATUS_UNKNOWN);
         setToggled(callForwardInfo.status == 1);
         boolean displayVoicemailNumber = false;
         if (TextUtils.isEmpty(callForwardInfo.number)) {
@@ -216,7 +238,7 @@
      */
     void startCallForwardOptionsQuery() {
         if (!mCallForwardByUssd) {
-            mPhone.getCallForwardingOption(reason,
+            mPhone.getCallForwardingOption(reason, mServiceClass,
                     mHandler.obtainMessage(MyHandler.MESSAGE_GET_CF,
                             // unused in this case
                             CommandsInterface.CF_ACTION_DISABLE,
@@ -342,6 +364,7 @@
             AsyncResult ar = (AsyncResult) msg.obj;
 
             callForwardInfo = null;
+            boolean summaryOff = false;
             if (ar.exception != null) {
                 Log.d(LOG_TAG, "handleGetCFResponse: ar.exception=" + ar.exception);
                 if (ar.exception instanceof CommandException) {
@@ -359,9 +382,8 @@
                     mTcpListener.onError(CallForwardEditPreference.this, RESPONSE_ERROR);
                 }
                 CallForwardInfo cfInfoArray[] = (CallForwardInfo[]) ar.result;
-                if (cfInfoArray.length == 0) {
+                if (cfInfoArray == null || cfInfoArray.length == 0) {
                     Log.d(LOG_TAG, "handleGetCFResponse: cfInfoArray.length==0");
-                    setEnabled(false);
                     mTcpListener.onError(CallForwardEditPreference.this, RESPONSE_ERROR);
                 } else {
                     for (int i = 0, length = cfInfoArray.length; i < length; i++) {
@@ -372,10 +394,16 @@
                             CallForwardInfo info = cfInfoArray[i];
                             handleCallForwardResult(info);
 
+                            summaryOff = (info.status == CommandsInterface.SS_STATUS_UNKNOWN);
+
+                            if (ar.userObj instanceof Throwable) {
+                                Log.d(LOG_TAG, "Skipped duplicated error dialog");
+                                continue;
+                            }
+
                             // Show an alert if we got a success response but
                             // with unexpected values.
-                            // Currently only handle the fail-to-disable case
-                            // since we haven't observed fail-to-enable.
+                            // Handle the fail-to-disable case.
                             if (msg.arg2 == MESSAGE_SET_CF &&
                                     msg.arg1 == CommandsInterface.CF_ACTION_DISABLE &&
                                     info.status == 1) {
@@ -399,7 +427,21 @@
                                 }
                                 AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
                                 builder.setNeutralButton(R.string.close_dialog, null);
-                                builder.setTitle(getContext().getText(R.string.error_updating_title));
+                                builder.setTitle(getContext()
+                                        .getText(R.string.error_updating_title));
+                                builder.setMessage(s);
+                                builder.setCancelable(true);
+                                builder.create().show();
+                            } else if (msg.arg2 == MESSAGE_SET_CF &&
+                                    msg.arg1 == CommandsInterface.CF_ACTION_REGISTRATION &&
+                                    info.status == 0) {
+                                // Handle the fail-to-enable case.
+                                CharSequence s = getContext()
+                                    .getText(R.string.registration_cf_forbidden);
+                                AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+                                builder.setNeutralButton(R.string.close_dialog, null);
+                                builder.setTitle(getContext()
+                                        .getText(R.string.error_updating_title));
                                 builder.setMessage(s);
                                 builder.setCancelable(true);
                                 builder.create().show();
@@ -412,7 +454,15 @@
             // Now whether or not we got a new number, reset our enabled
             // summary text since it may have been replaced by an empty
             // placeholder.
-            updateSummaryText();
+            // for CDMA, doesn't display summary.
+            if (summaryOff) {
+                setSummaryOff("");
+            } else {
+                // Now whether or not we got a new number, reset our enabled
+                // summary text since it may have been replaced by an empty
+                // placeholder.
+                updateSummaryText();
+            }
         }
 
         private void handleSetCFResponse(Message msg) {
@@ -421,9 +471,19 @@
                 Log.d(LOG_TAG, "handleSetCFResponse: ar.exception=" + ar.exception);
                 // setEnabled(false);
             }
+
+            if (ar.result != null) {
+                int arr = (int)ar.result;
+                if (arr == CommandsInterface.SS_STATUS_UNKNOWN) {
+                    Log.d(LOG_TAG, "handleSetCFResponse: no need to re get in CDMA");
+                    mTcpListener.onFinished(CallForwardEditPreference.this, false);
+                    return;
+                }
+            }
+
             Log.d(LOG_TAG, "handleSetCFResponse: re get");
             if (!mCallForwardByUssd) {
-                mPhone.getCallForwardingOption(reason,
+                mPhone.getCallForwardingOption(reason, mServiceClass,
                         obtainMessage(MESSAGE_GET_CF, msg.arg1, MESSAGE_SET_CF, ar.exception));
             } else {
                 mHandler.sendMessage(mHandler.obtainMessage(mHandler.MESSAGE_GET_CF_USSD,
diff --git a/src/com/android/phone/CallNotifier.java b/src/com/android/phone/CallNotifier.java
index dab04f0..23a9649 100644
--- a/src/com/android/phone/CallNotifier.java
+++ b/src/com/android/phone/CallNotifier.java
@@ -21,6 +21,7 @@
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.media.AudioManager;
+import android.media.AudioSystem;
 import android.media.ToneGenerator;
 import android.os.AsyncResult;
 import android.os.Handler;
@@ -392,10 +393,10 @@
             try {
                 int stream;
                 if (mBluetoothHeadset != null) {
-                    stream = isBluetoothAudioOn() ? AudioManager.STREAM_BLUETOOTH_SCO :
-                        AudioManager.STREAM_VOICE_CALL;
+                    stream = isBluetoothAudioOn() ? AudioSystem.STREAM_BLUETOOTH_SCO :
+                            AudioSystem.STREAM_VOICE_CALL;
                 } else {
-                    stream = AudioManager.STREAM_VOICE_CALL;
+                    stream = AudioSystem.STREAM_VOICE_CALL;
                 }
                 toneGenerator = new ToneGenerator(stream, toneVolume);
                 // if (DBG) log("- created toneGenerator: " + toneGenerator);
@@ -558,7 +559,8 @@
 
     public void updatePhoneStateListeners(boolean isRefresh, int updateType, int subIdToUpdate) {
         List<SubscriptionInfo> subInfos = SubscriptionController.getInstance()
-                .getActiveSubscriptionInfoList(mApplication.getOpPackageName());
+                .getActiveSubscriptionInfoList(mApplication.getOpPackageName(),
+                        null);
 
         // Sort sub id list based on slot id, so that CFI/MWI notifications will be updated for
         // slot 0 first then slot 1. This is needed to ensure that when CFI or MWI is enabled for
@@ -615,7 +617,7 @@
         for (int i = 0; i < subInfos.size(); i++) {
             int subId = subInfos.get(i).getSubscriptionId();
             if (!mPhoneStateListeners.containsKey(subId)) {
-                CallNotifierPhoneStateListener listener = new CallNotifierPhoneStateListener();
+                CallNotifierPhoneStateListener listener = new CallNotifierPhoneStateListener(subId);
                 mTelephonyManager.createForSubscriptionId(subId).listen(listener,
                         PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
                         | PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR);
@@ -767,8 +769,11 @@
             };
 
     private class CallNotifierPhoneStateListener extends PhoneStateListener {
-        public CallNotifierPhoneStateListener() {
+        private final int mSubId;
+
+        CallNotifierPhoneStateListener(int subId) {
             super();
+            this.mSubId = subId;
         }
 
         @Override
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index d451ccf..a816c89 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -57,13 +57,8 @@
 import com.android.internal.telephony.SubscriptionInfoUpdater;
 import com.android.internal.telephony.TelephonyPermissions;
 import com.android.internal.telephony.util.ArrayUtils;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
-
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
@@ -80,7 +75,6 @@
 /**
  * CarrierConfigLoader binds to privileged carrier apps to fetch carrier config overlays.
  */
-
 public class CarrierConfigLoader extends ICarrierConfigLoader.Stub {
     private static final String LOG_TAG = "CarrierConfigLoader";
 
@@ -101,6 +95,8 @@
     private PersistableBundle[] mOverrideConfigs;
     // Service connection for binding to config app.
     private CarrierServiceConnection[] mServiceConnection;
+    // Whether we are bound to a service for each phone
+    private boolean[] mServiceBound;
     // Whether we have sent config change bcast for each phone id.
     private boolean[] mHasSentConfigChange;
     // SubscriptionInfoUpdater
@@ -149,10 +145,8 @@
 
     private static final int BIND_TIMEOUT_MILLIS = 30000;
 
-    // Tags used for saving and restoring XML documents.
-    private static final String TAG_DOCUMENT = "carrier_config";
-    private static final String TAG_VERSION = "package_version";
-    private static final String TAG_BUNDLE = "bundle_data";
+    // Keys used for saving and restoring config bundle from file.
+    private static final String KEY_VERSION = "__carrier_config_package_version__";
 
     private static final String OVERRIDE_PACKAGE_ADDITION = "-override";
 
@@ -273,7 +267,7 @@
                     final CarrierServiceConnection conn = (CarrierServiceConnection) msg.obj;
                     // If new service connection has been created, unbind.
                     if (mServiceConnection[phoneId] != conn || conn.service == null) {
-                        mContext.unbindService(conn);
+                        unbindIfBound(mContext, conn, phoneId);
                         break;
                     }
                     final CarrierIdentifier carrierId = getCarrierIdentifierForPhoneId(phoneId);
@@ -282,7 +276,7 @@
                             new ResultReceiver(this) {
                                 @Override
                                 public void onReceiveResult(int resultCode, Bundle resultData) {
-                                    mContext.unbindService(conn);
+                                    unbindIfBound(mContext, conn, phoneId);
                                     // If new service connection has been created, this is stale.
                                     if (mServiceConnection[phoneId] != conn) {
                                         loge("Received response for stale request.");
@@ -316,7 +310,7 @@
                     } catch (RemoteException e) {
                         loge("Failed to get carrier config from default app: " +
                                 mPlatformCarrierConfigPackage + " err: " + e.toString());
-                        mContext.unbindService(conn);
+                        unbindIfBound(mContext, conn, phoneId);
                         break; // So we don't set a timeout.
                     }
                     sendMessageDelayed(
@@ -336,7 +330,7 @@
                     if (mServiceConnection[phoneId] != null) {
                         // If a ResponseReceiver callback is in the queue when this happens, we will
                         // unbind twice and throw an exception.
-                        mContext.unbindService(mServiceConnection[phoneId]);
+                        unbindIfBound(mContext, mServiceConnection[phoneId], phoneId);
                         broadcastConfigChangedIntent(phoneId);
                     }
                     notifySubscriptionInfoUpdater(phoneId);
@@ -402,7 +396,7 @@
                     final CarrierServiceConnection conn = (CarrierServiceConnection) msg.obj;
                     // If new service connection has been created, unbind.
                     if (mServiceConnection[phoneId] != conn || conn.service == null) {
-                        mContext.unbindService(conn);
+                        unbindIfBound(mContext, conn, phoneId);
                         break;
                     }
                     final CarrierIdentifier carrierId = getCarrierIdentifierForPhoneId(phoneId);
@@ -411,7 +405,7 @@
                             new ResultReceiver(this) {
                                 @Override
                                 public void onReceiveResult(int resultCode, Bundle resultData) {
-                                    mContext.unbindService(conn);
+                                    unbindIfBound(mContext, conn, phoneId);
                                     // If new service connection has been created, this is stale.
                                     if (mServiceConnection[phoneId] != conn) {
                                         loge("Received response for stale request.");
@@ -446,7 +440,7 @@
                                 + " carrierid: " + carrierId.toString());
                     } catch (RemoteException e) {
                         loge("Failed to get carrier config: " + e.toString());
-                        mContext.unbindService(conn);
+                        unbindIfBound(mContext, conn, phoneId);
                         break; // So we don't set a timeout.
                     }
                     sendMessageDelayed(
@@ -466,7 +460,7 @@
                     if (mServiceConnection[phoneId] != null) {
                         // If a ResponseReceiver callback is in the queue when this happens, we will
                         // unbind twice and throw an exception.
-                        mContext.unbindService(mServiceConnection[phoneId]);
+                        unbindIfBound(mContext, mServiceConnection[phoneId], phoneId);
                         broadcastConfigChangedIntent(phoneId);
                     }
                     notifySubscriptionInfoUpdater(phoneId);
@@ -545,6 +539,7 @@
         mPersistentOverrideConfigs = new PersistableBundle[numPhones];
         mOverrideConfigs = new PersistableBundle[numPhones];
         mServiceConnection = new CarrierServiceConnection[numPhones];
+        mServiceBound = new boolean[numPhones];
         mHasSentConfigChange = new boolean[numPhones];
         // Make this service available through ServiceManager.
         ServiceManager.addService(Context.CARRIER_CONFIG_SERVICE, this);
@@ -601,6 +596,10 @@
             configToSend = mConfigFromDefaultApp[phoneId];
         }
 
+        if (configToSend == null) {
+            configToSend = new PersistableBundle();
+        }
+
         // mOverrideConfigs is for testing. And it will override current configs.
         PersistableBundle config = mOverrideConfigs[phoneId];
         if (config != null) {
@@ -620,7 +619,6 @@
     private void broadcastConfigChangedIntent(int phoneId, boolean addSubIdExtra) {
         Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
-                Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND |
                 Intent.FLAG_RECEIVER_FOREGROUND);
         if (addSubIdExtra) {
             int simApplicationState = TelephonyManager.SIM_STATE_UNKNOWN;
@@ -652,8 +650,13 @@
         carrierService.setPackage(pkgName);
         mServiceConnection[phoneId] = new CarrierServiceConnection(phoneId, eventId);
         try {
-            return mContext.bindService(carrierService, mServiceConnection[phoneId],
-                    Context.BIND_AUTO_CREATE);
+            if (mContext.bindService(carrierService, mServiceConnection[phoneId],
+                    Context.BIND_AUTO_CREATE)) {
+                mServiceBound[phoneId] = true;
+                return true;
+            } else {
+                return false;
+            }
         } catch (SecurityException ex) {
             return false;
         }
@@ -793,27 +796,14 @@
             outFile = new FileOutputStream(
                     new File(mContext.getFilesDir(),
                             getFilenameForConfig(packageName, extraString, iccid, cid)));
-            FastXmlSerializer out = new FastXmlSerializer();
-            out.setOutput(outFile, "utf-8");
-            out.startDocument("utf-8", true);
-            out.startTag(null, TAG_DOCUMENT);
-            out.startTag(null, TAG_VERSION);
-            out.text(version);
-            out.endTag(null, TAG_VERSION);
-            out.startTag(null, TAG_BUNDLE);
-            config.saveToXml(out);
-            out.endTag(null, TAG_BUNDLE);
-            out.endTag(null, TAG_DOCUMENT);
-            out.endDocument();
-            out.flush();
+            config.putString(KEY_VERSION, version);
+            config.writeToStream(outFile);
+            outFile.flush();
             outFile.close();
         }
         catch (IOException e) {
             loge(e.toString());
         }
-        catch (XmlPullParserException e) {
-            loge(e.toString());
-        }
     }
 
     /**
@@ -858,24 +848,16 @@
             file = new File(mContext.getFilesDir(),
                     getFilenameForConfig(packageName, extraString, iccid, cid));
             inFile = new FileInputStream(file);
-            XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
-            parser.setInput(inFile, "utf-8");
 
-            int event;
-            while (((event = parser.next()) != XmlPullParser.END_DOCUMENT)) {
+            restoredBundle = PersistableBundle.readFromStream(inFile);
+            String savedVersion = restoredBundle.getString(KEY_VERSION);
+            restoredBundle.remove(KEY_VERSION);
 
-                if (event == XmlPullParser.START_TAG && TAG_VERSION.equals(parser.getName())) {
-                    String savedVersion = parser.nextText();
-                    if (!version.equals(savedVersion)) {
-                        loge("Saved version mismatch: " + version + " vs " + savedVersion);
-                        break;
-                    }
-                }
-
-                if (event == XmlPullParser.START_TAG && TAG_BUNDLE.equals(parser.getName())) {
-                    restoredBundle = PersistableBundle.restoreFromXml(parser);
-                }
+            if (!version.equals(savedVersion)) {
+                loge("Saved version mismatch: " + version + " vs " + savedVersion);
+                restoredBundle = null;
             }
+
             inFile.close();
         }
         catch (FileNotFoundException e) {
@@ -883,9 +865,6 @@
             // 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());
-        }
         catch (IOException e) {
             loge(e.toString());
         }
@@ -967,8 +946,14 @@
 
     @Override
     public @NonNull PersistableBundle getConfigForSubId(int subId, String callingPackage) {
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mContext, subId, callingPackage, "getCarrierConfig")) {
+        return getConfigForSubIdWithFeature(subId, callingPackage, null);
+    }
+
+    @Override
+    public @NonNull PersistableBundle getConfigForSubIdWithFeature(int subId, String callingPackage,
+            String callingFeatureId) {
+        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage,
+                callingFeatureId, "getCarrierConfig")) {
             return new PersistableBundle();
         }
 
@@ -1080,6 +1065,7 @@
             case IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR:
             case IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED:
             case IccCardConstants.INTENT_VALUE_ICC_UNKNOWN:
+            case IccCardConstants.INTENT_VALUE_ICC_NOT_READY:
                 mHandler.sendMessage(mHandler.obtainMessage(EVENT_CLEAR_CONFIG, phoneId, -1));
                 break;
             case IccCardConstants.INTENT_VALUE_ICC_LOADED:
@@ -1091,6 +1077,9 @@
 
     @Override
     public String getDefaultCarrierServicePackageName() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+                "getDefaultCarrierServicePackageName");
         return mPlatformCarrierConfigPackage;
     }
 
@@ -1149,6 +1138,14 @@
         }
     }
 
+    private void unbindIfBound(Context context, CarrierServiceConnection conn,
+            int phoneId) {
+        if (mServiceBound[phoneId]) {
+            mServiceBound[phoneId] = false;
+            context.unbindService(conn);
+        }
+    }
+
     private class CarrierServiceConnection implements ServiceConnection {
         int phoneId;
         int eventId;
@@ -1168,6 +1165,19 @@
 
         @Override
         public void onServiceDisconnected(ComponentName name) {
+            log("Disconnected from config app: " + name.flattenToString());
+            this.service = null;
+        }
+
+        @Override
+        public void onBindingDied(ComponentName name) {
+            log("Binding died from config app: " + name.flattenToString());
+            this.service = null;
+        }
+
+        @Override
+        public void onNullBinding(ComponentName name) {
+            log("Null binding from config app: " + name.flattenToString());
             this.service = null;
         }
     }
diff --git a/src/com/android/phone/CdmaCallForwardOptions.java b/src/com/android/phone/CdmaCallForwardOptions.java
new file mode 100644
index 0000000..a8d2e93
--- /dev/null
+++ b/src/com/android/phone/CdmaCallForwardOptions.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import android.app.ActionBar;
+import android.content.Intent;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.os.PersistableBundle;
+import android.preference.Preference;
+import android.preference.PreferenceScreen;
+import android.telephony.CarrierConfigManager;
+import android.util.Log;
+import android.view.MenuItem;
+
+import com.android.internal.telephony.CallForwardInfo;
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.Phone;
+
+import java.util.ArrayList;
+
+public class CdmaCallForwardOptions extends TimeConsumingPreferenceActivity {
+    private static final String LOG_TAG = "CdmaCallForwardOptions";
+
+    private static final String NUM_PROJECTION[] = {
+        android.provider.ContactsContract.CommonDataKinds.Phone.NUMBER
+    };
+
+    private static final String BUTTON_CFU_KEY   = "button_cfu_key";
+    private static final String BUTTON_CFB_KEY   = "button_cfb_key";
+    private static final String BUTTON_CFNRY_KEY = "button_cfnry_key";
+    private static final String BUTTON_CFNRC_KEY = "button_cfnrc_key";
+
+    private static final String KEY_TOGGLE = "toggle";
+    private static final String KEY_STATUS = "status";
+    private static final String KEY_NUMBER = "number";
+    private static final String KEY_ENABLE = "enable";
+
+    private CallForwardEditPreference mButtonCFU;
+    private CallForwardEditPreference mButtonCFB;
+    private CallForwardEditPreference mButtonCFNRy;
+    private CallForwardEditPreference mButtonCFNRc;
+
+    private final ArrayList<CallForwardEditPreference> mPreferences =
+            new ArrayList<CallForwardEditPreference> ();
+    private int mInitIndex= 0;
+
+    private boolean mFirstResume;
+    private Bundle mIcicle;
+    private Phone mPhone;
+    private SubscriptionInfoHelper mSubscriptionInfoHelper;
+    private boolean mReplaceInvalidCFNumbers;
+    private boolean mCallForwardByUssd;
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        addPreferencesFromResource(R.xml.callforward_options);
+
+        mSubscriptionInfoHelper = new SubscriptionInfoHelper(this, getIntent());
+        mSubscriptionInfoHelper.setActionBarTitle(
+                getActionBar(), getResources(), R.string.call_forwarding_settings_with_label);
+        mPhone = mSubscriptionInfoHelper.getPhone();
+
+        PersistableBundle b = null;
+        boolean supportCFNRc = true;
+        if (mSubscriptionInfoHelper.hasSubId()) {
+            b = PhoneGlobals.getInstance().getCarrierConfigForSubId(
+                    mSubscriptionInfoHelper.getSubId());
+        } else {
+            b = PhoneGlobals.getInstance().getCarrierConfig();
+        }
+        if (b != null) {
+            mReplaceInvalidCFNumbers = b.getBoolean(
+                    CarrierConfigManager.KEY_CALL_FORWARDING_MAP_NON_NUMBER_TO_VOICEMAIL_BOOL);
+            mCallForwardByUssd = b.getBoolean(
+                    CarrierConfigManager.KEY_USE_CALL_FORWARDING_USSD_BOOL);
+            supportCFNRc = b.getBoolean(
+                    CarrierConfigManager.KEY_CALL_FORWARDING_WHEN_UNREACHABLE_SUPPORTED_BOOL);
+        }
+
+        PreferenceScreen prefSet = getPreferenceScreen();
+        mButtonCFU = (CallForwardEditPreference) prefSet.findPreference(BUTTON_CFU_KEY);
+        mButtonCFB = (CallForwardEditPreference) prefSet.findPreference(BUTTON_CFB_KEY);
+        mButtonCFNRy = (CallForwardEditPreference) prefSet.findPreference(BUTTON_CFNRY_KEY);
+        mButtonCFNRc = (CallForwardEditPreference) prefSet.findPreference(BUTTON_CFNRC_KEY);
+
+        mButtonCFU.setParentActivity(this, mButtonCFU.reason);
+        mButtonCFB.setParentActivity(this, mButtonCFB.reason);
+        mButtonCFNRy.setParentActivity(this, mButtonCFNRy.reason);
+        mButtonCFNRc.setParentActivity(this, mButtonCFNRc.reason);
+
+        mPreferences.add(mButtonCFU);
+        mPreferences.add(mButtonCFB);
+        mPreferences.add(mButtonCFNRy);
+
+        if (supportCFNRc) {
+            mPreferences.add(mButtonCFNRc);
+        } else {
+            // When CFNRc is not supported, mButtonCFNRc is grayed out from the menu.
+            // Default state for the preferences in this PreferenceScreen is disabled.
+            // Only preferences listed in the ArrayList mPreferences will be enabled.
+            // By not adding mButtonCFNRc to mPreferences it will be kept disabled.
+            Log.d(LOG_TAG, "onCreate: CFNRc is not supported, grey out the item.");
+        }
+
+        if (mCallForwardByUssd) {
+            //the call forwarding ussd command's behavior is similar to the call forwarding when
+            //unanswered,so only display the call forwarding when unanswered item.
+            prefSet.removePreference(mButtonCFU);
+            prefSet.removePreference(mButtonCFB);
+            prefSet.removePreference(mButtonCFNRc);
+            mPreferences.remove(mButtonCFU);
+            mPreferences.remove(mButtonCFB);
+            mPreferences.remove(mButtonCFNRc);
+            mButtonCFNRy.setDependency(null);
+        }
+
+        // we wait to do the initialization until onResume so that the
+        // TimeConsumingPreferenceActivity dialog can display as it
+        // relies on onResume / onPause to maintain its foreground state.
+
+        mFirstResume = true;
+        mIcicle = icicle;
+
+        ActionBar actionBar = getActionBar();
+        if (actionBar != null) {
+            // android.R.id.home will be triggered in onOptionsItemSelected()
+            actionBar.setDisplayHomeAsUpEnabled(true);
+        }
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        if (mFirstResume) {
+            if (mIcicle == null) {
+                Log.d(LOG_TAG, "start to init ");
+                CallForwardEditPreference pref = mPreferences.get(mInitIndex);
+                pref.init(this, mPhone, mReplaceInvalidCFNumbers, mCallForwardByUssd);
+                pref.startCallForwardOptionsQuery();
+
+            } else {
+                mInitIndex = mPreferences.size();
+
+                for (CallForwardEditPreference pref : mPreferences) {
+                    Bundle bundle = mIcicle.getParcelable(pref.getKey());
+                    pref.setToggled(bundle.getBoolean(KEY_TOGGLE));
+                    pref.setEnabled(bundle.getBoolean(KEY_ENABLE));
+                    CallForwardInfo cf = new CallForwardInfo();
+                    cf.number = bundle.getString(KEY_NUMBER);
+                    cf.status = bundle.getInt(KEY_STATUS);
+                    pref.init(this, mPhone, mReplaceInvalidCFNumbers, mCallForwardByUssd);
+                    pref.restoreCallForwardInfo(cf);
+                }
+            }
+            mFirstResume = false;
+            mIcicle = null;
+        }
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+
+        for (CallForwardEditPreference pref : mPreferences) {
+            Bundle bundle = new Bundle();
+            bundle.putBoolean(KEY_TOGGLE, pref.isToggled());
+            bundle.putBoolean(KEY_ENABLE, pref.isEnabled());
+            if (pref.callForwardInfo != null) {
+                bundle.putString(KEY_NUMBER, pref.callForwardInfo.number);
+                bundle.putInt(KEY_STATUS, pref.callForwardInfo.status);
+            }
+            outState.putParcelable(pref.getKey(), bundle);
+        }
+    }
+
+    @Override
+    public void onFinished(Preference preference, boolean reading) {
+        if (mInitIndex < mPreferences.size()-1 && !isFinishing()) {
+            mInitIndex++;
+            CallForwardEditPreference pref = mPreferences.get(mInitIndex);
+            pref.init(this, mPhone, mReplaceInvalidCFNumbers, mCallForwardByUssd);
+            pref.startCallForwardOptionsQuery();
+        }
+
+        super.onFinished(preference, reading);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        Log.d(LOG_TAG, "onActivityResult: done");
+        if (resultCode != RESULT_OK) {
+            Log.d(LOG_TAG, "onActivityResult: contact picker result not OK.");
+            return;
+        }
+        Cursor cursor = null;
+        try {
+            cursor = getContentResolver().query(data.getData(),
+                NUM_PROJECTION, null, null, null);
+            if ((cursor == null) || (!cursor.moveToFirst())) {
+                Log.d(LOG_TAG, "onActivityResult: bad contact data, no results found.");
+                return;
+            }
+
+            switch (requestCode) {
+                case CommandsInterface.CF_REASON_UNCONDITIONAL:
+                    mButtonCFU.onPickActivityResult(cursor.getString(0));
+                    break;
+                case CommandsInterface.CF_REASON_BUSY:
+                    mButtonCFB.onPickActivityResult(cursor.getString(0));
+                    break;
+                case CommandsInterface.CF_REASON_NO_REPLY:
+                    mButtonCFNRy.onPickActivityResult(cursor.getString(0));
+                    break;
+                case CommandsInterface.CF_REASON_NOT_REACHABLE:
+                    mButtonCFNRc.onPickActivityResult(cursor.getString(0));
+                    break;
+                default:
+                    // TODO: may need exception here.
+            }
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        final int itemId = item.getItemId();
+        if (itemId == android.R.id.home) {  // See ActionBar#setDisplayHomeAsUpEnabled()
+            CallFeaturesSetting.goUpToTopLevelSetting(this, mSubscriptionInfoHelper);
+            return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+}
diff --git a/src/com/android/phone/CdmaCallOptions.java b/src/com/android/phone/CdmaCallOptions.java
index acfa496..8f4fa67 100644
--- a/src/com/android/phone/CdmaCallOptions.java
+++ b/src/com/android/phone/CdmaCallOptions.java
@@ -27,11 +27,13 @@
 
 import com.android.internal.telephony.PhoneConstants;
 
-public class CdmaCallOptions extends PreferenceActivity {
+public class CdmaCallOptions extends TimeConsumingPreferenceActivity {
     private static final String LOG_TAG = "CdmaCallOptions";
     private final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     private static final String BUTTON_VP_KEY = "button_voice_privacy_key";
+    private static final String CALL_FORWARDING_KEY = "call_forwarding_key";
+    private static final String CALL_WAITING_KEY = "call_waiting_key";
     private SwitchPreference mButtonVoicePrivacy;
 
     @Override
@@ -55,8 +57,15 @@
         if (subInfoHelper.getPhone().getPhoneType() != PhoneConstants.PHONE_TYPE_CDMA
                 || carrierConfig.getBoolean(CarrierConfigManager.KEY_VOICE_PRIVACY_DISABLE_UI_BOOL)) {
             // disable the entire screen
-            getPreferenceScreen().setEnabled(false);
+            mButtonVoicePrivacy.setEnabled(false);
         }
+
+        Preference callForwardingPref = getPreferenceScreen().findPreference(CALL_FORWARDING_KEY);
+        callForwardingPref.setIntent(subInfoHelper.getIntent(CdmaCallForwardOptions.class));
+
+        CdmaCallWaitingPreference callWaitingPref = (CdmaCallWaitingPreference)getPreferenceScreen()
+                                                     .findPreference(CALL_WAITING_KEY);
+        callWaitingPref.init(this, subInfoHelper.getPhone());
     }
 
     @Override
@@ -76,5 +85,4 @@
         }
         return false;
     }
-
 }
diff --git a/src/com/android/phone/CdmaCallWaitingPreference.java b/src/com/android/phone/CdmaCallWaitingPreference.java
new file mode 100644
index 0000000..4cda7ba
--- /dev/null
+++ b/src/com/android/phone/CdmaCallWaitingPreference.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import com.android.internal.telephony.CommandException;
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.Phone;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.TypedArray;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.util.AttributeSet;
+import android.util.Log;
+
+public class CdmaCallWaitingPreference extends Preference {
+    private static final String LOG_TAG = "CdmaCallWaitingPreference";
+    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
+
+    private int mButtonClicked;
+    private Context mContext;
+    private Phone mPhone;
+    private SubscriptionInfoHelper mSubscriptionInfoHelper;
+    private TimeConsumingPreferenceListener mTcpListener;
+    private MyHandler mHandler = new MyHandler();
+
+    public CdmaCallWaitingPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mContext = context;
+    }
+
+    public CdmaCallWaitingPreference(Context context, AttributeSet attrs) {
+        this(context, attrs, com.android.internal.R.attr.preferenceStyle);
+    }
+
+    public CdmaCallWaitingPreference(Context context) {
+        this(context, null);
+    }
+
+    public void init(TimeConsumingPreferenceListener listener, Phone phone) {
+        mPhone = phone;
+        mTcpListener = listener;
+        Log.d(LOG_TAG, "phone id= " + mPhone.getPhoneId());
+        mPhone.getCallWaiting(mHandler.obtainMessage(MyHandler.MESSAGE_GET_CALL_WAITING,
+                    MyHandler.MESSAGE_GET_CALL_WAITING, MyHandler.MESSAGE_GET_CALL_WAITING));
+        if (mTcpListener != null) {
+            mTcpListener.onStarted(this, true);
+        }
+    }
+
+    @Override
+    public void onClick() {
+        super.onClick();
+
+        AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+        builder.setTitle(mContext.getText(R.string.cdma_call_waiting));
+        builder.setMessage(mContext.getText(R.string.enable_cdma_call_waiting_setting));
+        builder.setPositiveButton(R.string.enable_cdma_cw, new DialogInterface.OnClickListener() {
+            public void onClick(DialogInterface dialog, int whichButton) {
+                mPhone.setCallWaiting(true,
+                        mHandler.obtainMessage(MyHandler.MESSAGE_SET_CALL_WAITING));
+                if (mTcpListener != null) {
+                    mTcpListener.onStarted(CdmaCallWaitingPreference.this, false);
+                }
+            }
+        });
+        builder.setNegativeButton(R.string.disable_cdma_cw, new DialogInterface.OnClickListener() {
+            public void onClick(DialogInterface dialog, int whichButton) {
+                mPhone.setCallWaiting(false,
+                        mHandler.obtainMessage(MyHandler.MESSAGE_SET_CALL_WAITING));
+                if (mTcpListener != null) {
+                    mTcpListener.onStarted(CdmaCallWaitingPreference.this, false);
+                }
+            }
+        });
+        builder.create().show();
+    }
+
+    private class MyHandler extends Handler {
+        static final int MESSAGE_GET_CALL_WAITING = 0;
+        static final int MESSAGE_SET_CALL_WAITING = 1;
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MESSAGE_GET_CALL_WAITING:
+                    handleGetCallWaitingResponse(msg);
+                    break;
+                case MESSAGE_SET_CALL_WAITING:
+                    handleSetCallWaitingResponse(msg);
+                    break;
+            }
+        }
+
+        private void handleGetCallWaitingResponse(Message msg) {
+            AsyncResult ar = (AsyncResult) msg.obj;
+
+            if (mTcpListener != null) {
+                if (msg.arg2 == MESSAGE_SET_CALL_WAITING) {
+                    mTcpListener.onFinished(CdmaCallWaitingPreference.this, false);
+                } else {
+                    mTcpListener.onFinished(CdmaCallWaitingPreference.this, true);
+                }
+            }
+
+            if (ar.exception instanceof CommandException) {
+                if (DBG) {
+                    Log.d(LOG_TAG, "handleGetCallWaitingResponse: CommandException=" +
+                            ar.exception);
+                }
+                if (mTcpListener != null) {
+                    mTcpListener.onException(CdmaCallWaitingPreference.this,
+                                             (CommandException)ar.exception);
+                }
+            } else if (ar.userObj instanceof Throwable || ar.exception != null) {
+                if (DBG) {
+                    Log.d(LOG_TAG, "handleGetCallWaitingResponse: Exception" + ar.exception);
+                }
+                if (mTcpListener != null) {
+                    mTcpListener.onError(CdmaCallWaitingPreference.this,
+                                         TimeConsumingPreferenceActivity.RESPONSE_ERROR);
+                }
+            } else {
+                if (DBG) {
+                    Log.d(LOG_TAG, "handleGetCallWaitingResponse: CW state successfully queried.");
+                }
+                int[] cwArray = (int[])ar.result;
+                if (cwArray == null) {
+                    if (mTcpListener != null) {
+                        mTcpListener.onError(CdmaCallWaitingPreference.this,
+                                             TimeConsumingPreferenceActivity.RESPONSE_ERROR);
+                    }
+                    return;
+                }
+
+                try {
+                    if (cwArray[0] == CommandsInterface.SS_STATUS_UNKNOWN) {
+                        setSummary("");
+                    } else if(cwArray[0] == 1) {
+                        setSummary(mContext.getString(R.string.cdma_call_waiting_in_ims_on));
+                    } else if(cwArray[0] == 0) {
+                        setSummary(mContext.getString(R.string.cdma_call_waiting_in_ims_off));
+                    }
+                } catch (ArrayIndexOutOfBoundsException e) {
+                    setSummary("");
+                    Log.e(LOG_TAG, "handleGetCallWaitingResponse: improper result: err ="
+                            + e.getMessage());
+                }
+            }
+        }
+
+        private void handleSetCallWaitingResponse(Message msg) {
+            AsyncResult ar = (AsyncResult) msg.obj;
+
+            if (ar.exception != null) {
+                if (DBG) {
+                    Log.d(LOG_TAG, "handleSetCallWaitingResponse: ar.exception=" + ar.exception);
+                }
+            }
+
+            if (ar.result != null) {
+                int arr = (int)ar.result;
+                if (arr == CommandsInterface.SS_STATUS_UNKNOWN) {
+                    Log.d(LOG_TAG, "handleSetCallWaitingResponse: no need to re get in CDMA");
+                    mTcpListener.onFinished(CdmaCallWaitingPreference.this, false);
+                    return;
+                }
+            }
+
+            if (DBG) Log.d(LOG_TAG, "handleSetCallWaitingResponse: re get");
+            mPhone.getCallWaiting(obtainMessage(MESSAGE_GET_CALL_WAITING,
+                        MESSAGE_SET_CALL_WAITING, MESSAGE_SET_CALL_WAITING, ar.exception));
+        }
+    }
+}
diff --git a/src/com/android/phone/CellInfoUtil.java b/src/com/android/phone/CellInfoUtil.java
index 8272029..f6d741f 100644
--- a/src/com/android/phone/CellInfoUtil.java
+++ b/src/com/android/phone/CellInfoUtil.java
@@ -33,6 +33,7 @@
 
 import com.android.internal.telephony.OperatorInfo;
 
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -149,7 +150,8 @@
                 mcc,
                 mnc,
                 operatorInfo.getOperatorAlphaLong(),
-                operatorInfo.getOperatorAlphaShort());
+                operatorInfo.getOperatorAlphaShort(),
+                Collections.emptyList());
 
         CellInfoGsm ci = new CellInfoGsm();
         ci.setCellIdentity(cig);
diff --git a/src/com/android/phone/EditPhoneNumberPreference.java b/src/com/android/phone/EditPhoneNumberPreference.java
index 35af20d..505c284 100644
--- a/src/com/android/phone/EditPhoneNumberPreference.java
+++ b/src/com/android/phone/EditPhoneNumberPreference.java
@@ -16,6 +16,9 @@
 
 package com.android.phone;
 
+import static android.view.View.LAYOUT_DIRECTION_LOCALE;
+import static android.view.View.TEXT_DIRECTION_LOCALE;
+
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.content.Context;
@@ -37,6 +40,8 @@
 import android.widget.ImageButton;
 import android.widget.TextView;
 
+import com.android.internal.telephony.CommandsInterface;
+
 public class EditPhoneNumberPreference extends EditTextPreference {
 
     //allowed modes for this preference.
@@ -90,6 +95,7 @@
     private String mPhoneNumber;
     private boolean mChecked;
 
+    private boolean mIsUnknownStatus;
 
     /**
      * Interface for the dialog closed listener, related to
@@ -136,9 +142,9 @@
         a.recycle();
 
         //get the summary settings, use CheckBoxPreference as the standard.
-        a = context.obtainStyledAttributes(attrs, R.styleable.CheckBoxPreference, 0, 0);
-        mSummaryOn = a.getString(R.styleable.CheckBoxPreference_summaryOn);
-        mSummaryOff = a.getString(R.styleable.CheckBoxPreference_summaryOff);
+        a = context.obtainStyledAttributes(attrs, android.R.styleable.CheckBoxPreference, 0, 0);
+        mSummaryOn = a.getString(android.R.styleable.CheckBoxPreference_summaryOn);
+        mSummaryOff = a.getString(android.R.styleable.CheckBoxPreference_summaryOff);
         a.recycle();
     }
 
@@ -209,7 +215,9 @@
                 }
             }
             editText.setText(BidiFormatter.getInstance().unicodeWrap(
-                    mPhoneNumber, TextDirectionHeuristics.LTR));
+                    mPhoneNumber, TextDirectionHeuristics.LOCALE));
+            editText.setTextDirection(TEXT_DIRECTION_LOCALE);
+            editText.setLayoutDirection(LAYOUT_DIRECTION_LOCALE);
             editText.setMovementMethod(ArrowKeyMovementMethod.getInstance());
             editText.setKeyListener(DialerKeyListener.getInstance());
             editText.setOnFocusChangeListener(mDialogFocusChangeListener);
@@ -254,7 +262,13 @@
         // displayed, since there is no need to hide the edittext
         // field anymore.
         if (mConfirmationMode == CM_ACTIVATION) {
-            if (mChecked) {
+            if (mIsUnknownStatus) {
+                builder.setPositiveButton(mEnableText, this);
+                builder.setNeutralButton(mDisableText, this);
+                if (mPrefId == CommandsInterface.CF_REASON_ALL) {
+                    builder.setPositiveButton(null, null);
+                }
+            } else if (mChecked) {
                 builder.setPositiveButton(mChangeNumberText, this);
                 builder.setNeutralButton(mDisableText, this);
             } else {
@@ -310,7 +324,8 @@
     @Override
     public void onClick(DialogInterface dialog, int which) {
         // The neutral button (button3) is always the toggle.
-        if ((mConfirmationMode == CM_ACTIVATION) && (which == DialogInterface.BUTTON_NEUTRAL)) {
+        if ((mConfirmationMode == CM_ACTIVATION) && (which == DialogInterface.BUTTON_NEUTRAL)
+             && !mIsUnknownStatus) {
             //flip the toggle if we are in the correct mode.
             setToggled(!isToggled());
         }
@@ -499,4 +514,12 @@
     public void showPhoneNumberDialog() {
         showDialog(null);
     }
+
+    public void setUnknownStatus(boolean isUnknown) {
+        mIsUnknownStatus = isUnknown;
+    }
+
+    public boolean isUnknownStatus() {
+        return mIsUnknownStatus;
+    }
 }
diff --git a/src/com/android/phone/EmergencyActionGroup.java b/src/com/android/phone/EmergencyActionGroup.java
index 53ec1eb..4961a69 100644
--- a/src/com/android/phone/EmergencyActionGroup.java
+++ b/src/com/android/phone/EmergencyActionGroup.java
@@ -159,7 +159,7 @@
 
         if (v.getId() == R.id.action1 || v.getId() == R.id.action2 || v.getId() == R.id.action3) {
             AccessibilityManager accessibilityMgr =
-                    (AccessibilityManager) mContext.getSystemService(
+                    (AccessibilityManager) getContext().getSystemService(
                             Context.ACCESSIBILITY_SERVICE);
             if (accessibilityMgr.isTouchExplorationEnabled()) {
                 getContext().startActivity(intent);
diff --git a/src/com/android/phone/EmergencyCallbackModeExitDialog.java b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
index dcfa024..1210627 100644
--- a/src/com/android/phone/EmergencyCallbackModeExitDialog.java
+++ b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
@@ -35,6 +35,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 
 import com.android.internal.telephony.Phone;
@@ -300,8 +301,14 @@
             return String.format(getResources().getQuantityText(
                     R.plurals.alert_dialog_not_avaialble_in_ecm, minutes).toString(), time);
         case EXIT_ECM_DIALOG:
-            return String.format(getResources().getQuantityText(R.plurals.alert_dialog_exit_ecm,
-                    minutes).toString(), time);
+                boolean shouldRestrictData = mPhone.getImsPhone() != null
+                        && mPhone.getImsPhone().isInImsEcm();
+                return String.format(getResources().getQuantityText(
+                        // During IMS ECM, data restriction hint should be removed.
+                        shouldRestrictData
+                        ? R.plurals.alert_dialog_exit_ecm_without_data_restriction_hint
+                        : R.plurals.alert_dialog_exit_ecm,
+                        minutes).toString(), time);
         }
         return null;
     }
@@ -324,7 +331,8 @@
             // Received exit Emergency Callback Mode notification close all dialogs
             if (intent.getAction().equals(
                     TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
-                if (intent.getBooleanExtra("phoneinECMState", false) == false) {
+                // Cancel if the sticky broadcast extra for whether or not we are in ECM is false.
+                if (!intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false)) {
                     if (mAlertDialog != null)
                         mAlertDialog.dismiss();
                     if (mProgressDialog != null)
diff --git a/src/com/android/phone/EmergencyCallbackModeService.java b/src/com/android/phone/EmergencyCallbackModeService.java
index a07f7aa..6b247bd 100644
--- a/src/com/android/phone/EmergencyCallbackModeService.java
+++ b/src/com/android/phone/EmergencyCallbackModeService.java
@@ -30,13 +30,14 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
-import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.sysprop.TelephonyProperties;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.util.NotificationChannelController;
 
 import java.text.SimpleDateFormat;
@@ -50,7 +51,7 @@
 public class EmergencyCallbackModeService extends Service {
 
     // Default Emergency Callback Mode timeout value
-    private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
+    private static final long DEFAULT_ECM_EXIT_TIMER_VALUE = 300000L;
     private static final String LOG_TAG = "EmergencyCallbackModeService";
 
     private NotificationManager mNotificationManager = null;
@@ -106,7 +107,8 @@
             mPhone.unregisterForEcmTimerReset(mHandler);
 
             // Cancel the notification and timer
-            mNotificationManager.cancel(R.string.phone_in_ecm_notification_title);
+            mNotificationManager.cancelAsUser(null, R.string.phone_in_ecm_notification_title,
+                    UserHandle.ALL);
             mTimer.cancel();
         }
     }
@@ -120,7 +122,7 @@
             // Stop the service when phone exits Emergency Callback Mode
             if (intent.getAction().equals(
                     TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
-                if (intent.getBooleanExtra("phoneinECMState", false) == false) {
+                if (!intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false)) {
                     stopSelf();
                 }
             }
@@ -139,8 +141,7 @@
      */
     private void startTimerNotification() {
         // Get Emergency Callback Mode timeout value
-        long ecmTimeout = SystemProperties.getLong(
-                    TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
+        long ecmTimeout = TelephonyProperties.ecm_exit_timer().orElse(DEFAULT_ECM_EXIT_TIMER_VALUE);
 
         // Show the notification
         showNotification(ecmTimeout);
@@ -196,7 +197,11 @@
         // Format notification string
         String text = null;
         if(mInEmergencyCall) {
-            text = getText(R.string.phone_in_ecm_call_notification_text).toString();
+            text = getText(
+                    // During IMS ECM, data restriction hint should be removed.
+                    (imsPhone != null && imsPhone.isInImsEcm())
+                    ? R.string.phone_in_ecm_call_notification_text_without_data_restriction_hint
+                    : R.string.phone_in_ecm_call_notification_text).toString();
         } else {
             // Calculate the time in ms when the notification will be finished.
             long finishedCountMs = millisUntilFinished + System.currentTimeMillis();
@@ -207,14 +212,19 @@
 
             String completeTime = SimpleDateFormat.getTimeInstance(SimpleDateFormat.SHORT).format(
                     finishedCountMs);
-            text = getResources().getString(R.string.phone_in_ecm_notification_complete_time,
+            text = getResources().getString(
+                    // During IMS ECM, data restriction hint should be removed.
+                    (imsPhone != null && imsPhone.isInImsEcm())
+                    ? R.string.phone_in_ecm_notification_complete_time_without_data_restriction_hint
+                    : R.string.phone_in_ecm_notification_complete_time,
                     completeTime);
         }
         builder.setContentText(text);
         builder.setChannelId(NotificationChannelController.CHANNEL_ID_ALERT);
 
         // Show notification
-        mNotificationManager.notify(R.string.phone_in_ecm_notification_title, builder.build());
+        mNotificationManager.notifyAsUser(null, R.string.phone_in_ecm_notification_title,
+                builder.build(), UserHandle.ALL);
     }
 
     /**
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index 7531aca..334442f 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -45,7 +45,7 @@
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -720,8 +720,12 @@
             isEmergencyNumber = true;
             phoneToMakeCall = mShortcutViewConfig.getPhoneInfo();
         } else {
-            isEmergencyNumber = getSystemService(TelephonyManager.class)
-                    .isEmergencyNumber(mLastNumber);
+            try {
+                isEmergencyNumber = getSystemService(TelephonyManager.class)
+                        .isEmergencyNumber(mLastNumber);
+            } catch (IllegalStateException ise) {
+                isEmergencyNumber = false;
+            }
         }
 
         if (isEmergencyNumber) {
diff --git a/src/com/android/phone/EmergencyInfoGroup.java b/src/com/android/phone/EmergencyInfoGroup.java
index f5aca7f..a62edfd 100644
--- a/src/com/android/phone/EmergencyInfoGroup.java
+++ b/src/com/android/phone/EmergencyInfoGroup.java
@@ -209,7 +209,7 @@
     public void onClick(View view) {
         if (view.getId() == R.id.emergency_info_view) {
             AccessibilityManager accessibilityMgr =
-                    (AccessibilityManager) mContext.getSystemService(
+                    (AccessibilityManager) getContext().getSystemService(
                             Context.ACCESSIBILITY_SERVICE);
             if (accessibilityMgr.isTouchExplorationEnabled()) {
                 if (mOnConfirmClickListener != null) {
diff --git a/src/com/android/phone/EmergencyShortcutButton.java b/src/com/android/phone/EmergencyShortcutButton.java
index d147ce4..bfa956c 100644
--- a/src/com/android/phone/EmergencyShortcutButton.java
+++ b/src/com/android/phone/EmergencyShortcutButton.java
@@ -184,7 +184,7 @@
     public void onClick(View view) {
         if (view.getId() == R.id.emergency_call_number_info_view) {
             AccessibilityManager accessibilityMgr =
-                    (AccessibilityManager) mContext.getSystemService(
+                    (AccessibilityManager) getContext().getSystemService(
                             Context.ACCESSIBILITY_SERVICE);
             if (accessibilityMgr.isTouchExplorationEnabled()) {
                 // TalkBack itself includes a prompt to confirm click action implicitly,
diff --git a/src/com/android/phone/GsmUmtsCallBarringOptions.java b/src/com/android/phone/GsmUmtsCallBarringOptions.java
index 3c9cd84..30e9b5c 100644
--- a/src/com/android/phone/GsmUmtsCallBarringOptions.java
+++ b/src/com/android/phone/GsmUmtsCallBarringOptions.java
@@ -37,7 +37,6 @@
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.GsmCdmaPhone;
 import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.phone.settings.fdn.EditPinPreference;
 
 import java.util.ArrayList;
@@ -75,7 +74,6 @@
     private static final String DIALOG_PW_ENTRY_KEY = "dialog_pw_enter_key";
     private static final String KEY_STATUS = "toggle";
     private static final String PREFERENCE_ENABLED_KEY = "PREFERENCE_ENABLED";
-    private static final String PREFERENCE_SHOW_PASSWORD_KEY = "PREFERENCE_SHOW_PASSWORD";
     private static final String SAVED_BEFORE_LOAD_COMPLETED_KEY = "PROGRESS_SHOWING";
 
     private CallBarringEditPreference mButtonBAOC;
@@ -141,16 +139,13 @@
             return;
         }
 
-        String password = null;
-        if (mButtonDisableAll.isPasswordShown()) {
-            password = mButtonDisableAll.getText();
-            // Validate the length of password first, before submitting it to the
-            // RIL for CB disable.
-            if (!validatePassword(password)) {
-                mButtonDisableAll.setText("");
-                displayMessage(R.string.call_barring_right_pwd_number);
-                return;
-            }
+        String password = mButtonDisableAll.getText();
+        // Validate the length of password first, before submitting it to the
+        // RIL for CB disable.
+        if (!validatePassword(password)) {
+            mButtonDisableAll.setText("");
+            displayMessage(R.string.call_barring_right_pwd_number);
+            return;
         }
 
         // Submit the disable all request
@@ -417,34 +412,18 @@
         mPreferences.add(mButtonBAIC);
         mPreferences.add(mButtonBAICr);
 
-        // Find out if password is currently used.
-        boolean usePassword = true;
-        boolean useDisableaAll = true;
-
-        ImsPhone imsPhone = mPhone != null ? (ImsPhone) mPhone.getImsPhone() : null;
-        if (imsPhone != null && imsPhone.isUtEnabled()) {
-            usePassword = false;
-            useDisableaAll = false;
-        }
-
         // Find out if the sim card is ready.
         boolean isSimReady = TelephonyManager.from(this).getSimState(
                 SubscriptionManager.getSlotIndex(mPhone.getSubId()))
                         == TelephonyManager.SIM_STATE_READY;
 
-        // Deactivate all option is unavailable when sim card is not ready or Ut is enabled.
-        if (isSimReady && useDisableaAll) {
+        // Deactivate all option and Change password option are unavailable
+        // when sim card is not ready.
+        if (isSimReady) {
             mButtonDisableAll.setEnabled(true);
-            mButtonDisableAll.init(mPhone);
-        } else {
-            mButtonDisableAll.setEnabled(false);
-        }
-
-        // Change password option is unavailable when sim card is not ready or when the password is
-        // not used.
-        if (isSimReady && usePassword) {
             mButtonChangePW.setEnabled(true);
         } else {
+            mButtonDisableAll.setEnabled(false);
             mButtonChangePW.setEnabled(false);
             mButtonChangePW.setSummary(R.string.call_barring_change_pwd_description_disabled);
         }
@@ -472,8 +451,6 @@
                     pref.handleCallBarringResult(bundle.getBoolean(KEY_STATUS));
                     pref.init(this, true, mPhone);
                     pref.setEnabled(bundle.getBoolean(PREFERENCE_ENABLED_KEY, pref.isEnabled()));
-                    pref.setInputMethodNeeded(bundle.getBoolean(PREFERENCE_SHOW_PASSWORD_KEY,
-                            pref.needInputMethod()));
                 }
             }
             mPwChangeState = mIcicle.getInt(PW_CHANGE_STATE_KEY);
@@ -513,7 +490,6 @@
             Bundle bundle = new Bundle();
             bundle.putBoolean(KEY_STATUS, pref.mIsActivated);
             bundle.putBoolean(PREFERENCE_ENABLED_KEY, pref.isEnabled());
-            bundle.putBoolean(PREFERENCE_SHOW_PASSWORD_KEY, pref.needInputMethod());
             outState.putParcelable(pref.getKey(), bundle);
         }
         outState.putInt(PW_CHANGE_STATE_KEY, mPwChangeState);
diff --git a/src/com/android/phone/IccPanel.java b/src/com/android/phone/IccPanel.java
index be182233..73dd8bc 100644
--- a/src/com/android/phone/IccPanel.java
+++ b/src/com/android/phone/IccPanel.java
@@ -74,13 +74,13 @@
     @Override
     protected void onStart() {
         super.onStart();
-        mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND);
+        mStatusBarManager.setDisabledForSimNetworkLock(true);
     }
 
     @Override
     public void onStop() {
         super.onStop();
-        mStatusBarManager.disable(StatusBarManager.DISABLE_NONE);
+        mStatusBarManager.setDisabledForSimNetworkLock(false);
     }
 
     public boolean onKeyDown(int keyCode, KeyEvent event) {
diff --git a/src/com/android/phone/ImsRcsController.java b/src/com/android/phone/ImsRcsController.java
index 06d2367..3ea8df2 100644
--- a/src/com/android/phone/ImsRcsController.java
+++ b/src/com/android/phone/ImsRcsController.java
@@ -22,17 +22,24 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
+import android.telephony.SubscriptionManager;
 import android.telephony.ims.ImsException;
+import android.telephony.ims.RegistrationManager;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
 import android.telephony.ims.aidl.IImsRcsController;
+import android.telephony.ims.aidl.IImsRegistrationCallback;
 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.ims.ImsManager;
+import com.android.internal.telephony.IIntegerConsumer;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.imsphone.ImsPhone;
+import com.android.services.telephony.rcs.RcsFeatureController;
+import com.android.services.telephony.rcs.TelephonyRcsService;
+import com.android.services.telephony.rcs.UserCapabilityExchangeImpl;
 
 import java.util.List;
 
@@ -46,6 +53,7 @@
     private static ImsRcsController sInstance;
 
     private PhoneGlobals mApp;
+    private TelephonyRcsService mRcsService;
 
     /**
      * Initialize the singleton ImsRcsController instance.
@@ -70,6 +78,86 @@
     }
 
     /**
+     * Register a {@link RegistrationManager.RegistrationCallback} to receive IMS network
+     * registration state.
+     */
+    @Override
+    public void registerImsRegistrationCallback(int subId, IImsRegistrationCallback callback) {
+        enforceReadPrivilegedPermission("registerImsRegistrationCallback");
+        final long token = Binder.clearCallingIdentity();
+        try {
+            getRcsFeatureController(subId).registerImsRegistrationCallback(subId, callback);
+        } catch (ImsException e) {
+            Log.e(TAG, "registerImsRegistrationCallback: sudId=" + subId + ", " + e.getMessage());
+            throw new ServiceSpecificException(e.getCode());
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    /**
+     * Removes an existing {@link RegistrationManager.RegistrationCallback}.
+     */
+    @Override
+    public void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback callback) {
+        enforceReadPrivilegedPermission("unregisterImsRegistrationCallback");
+        final long token = Binder.clearCallingIdentity();
+        try {
+            getRcsFeatureController(subId).unregisterImsRegistrationCallback(subId, callback);
+        } catch (ServiceSpecificException e) {
+            Log.e(TAG, "unregisterImsRegistrationCallback: error=" + e.errorCode);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    /**
+     * Get the IMS service registration state for the RcsFeature associated with this sub id.
+     */
+    @Override
+    public void getImsRcsRegistrationState(int subId, IIntegerConsumer consumer) {
+        enforceReadPrivilegedPermission("getImsRcsRegistrationState");
+        final long token = Binder.clearCallingIdentity();
+        try {
+            getRcsFeatureController(subId).getRegistrationState(regState -> {
+                try {
+                    consumer.accept((regState == null)
+                            ? RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED : regState);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "getImsRcsRegistrationState: callback is not available.");
+                }
+            });
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    /**
+     * Gets the Transport Type associated with the current IMS RCS registration.
+     */
+    @Override
+    public void getImsRcsRegistrationTransportType(int subId, IIntegerConsumer consumer) {
+        enforceReadPrivilegedPermission("getImsRcsRegistrationTransportType");
+        final long token = Binder.clearCallingIdentity();
+        try {
+            getRcsFeatureController(subId).getRegistrationTech(regTech -> {
+                // Convert registration tech from ImsRegistrationImplBase -> RegistrationManager
+                int regTechConverted = (regTech == null)
+                        ? ImsRegistrationImplBase.REGISTRATION_TECH_NONE : regTech;
+                regTechConverted = RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.get(
+                        regTechConverted);
+                try {
+                    consumer.accept(regTechConverted);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "getImsRcsRegistrationTransportType: callback is not available.");
+                }
+            });
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    /**
      * Register a capability callback which will provide RCS availability updates for the
      * subscription specified.
      *
@@ -77,13 +165,12 @@
      * @param callback The ImsCapabilityCallback to be registered.
      */
     @Override
-    public void registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback)
-            throws RemoteException {
+    public void registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback) {
         enforceReadPrivilegedPermission("registerRcsAvailabilityCallback");
         final long token = Binder.clearCallingIdentity();
         try {
-            getRcsFeatureManager(subId).registerRcsAvailabilityCallback(callback);
-        } catch (com.android.ims.ImsException e) {
+            getRcsFeatureController(subId).registerRcsAvailabilityCallback(subId, callback);
+        } catch (ImsException e) {
             Log.e(TAG, "registerRcsAvailabilityCallback: sudId=" + subId + ", " + e.getMessage());
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -102,9 +189,7 @@
         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());
+            getRcsFeatureController(subId).unregisterRcsAvailabilityCallback(subId, callback);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -125,8 +210,8 @@
         enforceReadPrivilegedPermission("isCapable");
         final long token = Binder.clearCallingIdentity();
         try {
-            return getRcsFeatureManager(subId).isCapable(capability, radioTech);
-        } catch (com.android.ims.ImsException e) {
+            return getRcsFeatureController(subId).isCapable(capability, radioTech);
+        } catch (ImsException e) {
             Log.e(TAG, "isCapable: sudId=" + subId
                     + ", capability=" + capability + ", " + e.getMessage());
             return false;
@@ -149,8 +234,8 @@
         enforceReadPrivilegedPermission("isAvailable");
         final long token = Binder.clearCallingIdentity();
         try {
-            return getRcsFeatureManager(subId).isAvailable(capability);
-        } catch (com.android.ims.ImsException e) {
+            return getRcsFeatureController(subId).isAvailable(capability);
+        } catch (ImsException e) {
             Log.e(TAG, "isAvailable: sudId=" + subId
                     + ", capability=" + capability + ", " + e.getMessage());
             return false;
@@ -163,23 +248,49 @@
     public void requestCapabilities(int subId, List<Uri> contactNumbers,
             IRcsUceControllerCallback c) {
         enforceReadPrivilegedPermission("requestCapabilities");
+        final long token = Binder.clearCallingIdentity();
+        try {
+            UserCapabilityExchangeImpl uce = getRcsFeatureController(subId).getFeature(
+                    UserCapabilityExchangeImpl.class);
+            if (uce == null) {
+                throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+                        "This subscription does not support UCE.");
+            }
+            uce.requestCapabilities(contactNumbers, c);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     @Override
     public int getUcePublishState(int subId) {
         enforceReadPrivilegedPermission("getUcePublishState");
-        return -1;
+        final long token = Binder.clearCallingIdentity();
+        try {
+            UserCapabilityExchangeImpl uce = getRcsFeatureController(subId).getFeature(
+                    UserCapabilityExchangeImpl.class);
+            if (uce == null) {
+                throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+                        "This subscription does not support UCE.");
+            }
+            return uce.getUcePublishState();
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     @Override
     public boolean isUceSettingEnabled(int subId) {
         enforceReadPrivilegedPermission("isUceSettingEnabled");
-        return false;
+        return SubscriptionManager.getBooleanSubscriptionProperty(subId,
+                SubscriptionManager.IMS_RCS_UCE_ENABLED, false /*defaultValue*/, mApp);
     }
 
     @Override
     public void setUceSettingEnabled(int subId, boolean isEnabled) {
         enforceModifyPermission();
+        SubscriptionManager.setSubscriptionProperty(subId, SubscriptionManager.IMS_RCS_UCE_ENABLED,
+                (isEnabled ? "1" : "0"));
     }
 
     /**
@@ -202,13 +313,17 @@
     }
 
     /**
-     * Retrieve RcsFeatureManager instance.
+     * Retrieve ImsPhone instance.
      *
      * @param subId the subscription ID
-     * @return The RcsFeatureManager instance
-     * @throws SecurityException if getting Phone or RcsFeatureManager instance failed.
+     * @return The ImsPhone instance
+     * @throws ServiceSpecificException if getting ImsPhone instance failed.
      */
-    private RcsFeatureManager getRcsFeatureManager(int subId) {
+    private ImsPhone getImsPhone(int subId) {
+        if (!ImsManager.isImsSupportedOnDevice(mApp)) {
+            throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+                    "IMS is not available on device.");
+        }
         Phone phone = PhoneGlobals.getPhone(subId);
         if (phone == null) {
             throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION,
@@ -216,14 +331,43 @@
         }
         ImsPhone imsPhone = (ImsPhone) phone.getImsPhone();
         if (imsPhone == null) {
-            throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+            throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
                     "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 imsPhone;
+    }
+
+    /**
+     * Retrieve RcsFeatureManager instance.
+     *
+     * @param subId the subscription ID
+     * @return The RcsFeatureManager instance
+     * @throws ServiceSpecificException if getting RcsFeatureManager instance failed.
+     */
+    private RcsFeatureController getRcsFeatureController(int subId) {
+        if (!ImsManager.isImsSupportedOnDevice(mApp)) {
+            throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+                    "IMS is not available on device.");
         }
-        return rcsFeatureManager;
+        if (mRcsService == null) {
+            throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+                    "IMS is not available on device.");
+        }
+        Phone phone = PhoneGlobals.getPhone(subId);
+        if (phone == null) {
+            throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION,
+                    "Invalid subscription Id: " + subId);
+        }
+        int slotId = phone.getPhoneId();
+        RcsFeatureController c = mRcsService.getFeatureController(slotId);
+        if (c == null) {
+            throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+                    "The requested operation is not supported for subId " + subId);
+        }
+        return c;
+    }
+
+    void setRcsService(TelephonyRcsService rcsService) {
+        mRcsService = rcsService;
     }
 }
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index fe55335..fccceec 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -470,7 +470,7 @@
 
     private Intent getShowVoicemailIntentForDefaultDialer(UserHandle userHandle) {
         String dialerPackage = mContext.getSystemService(TelecomManager.class)
-                .getDefaultDialerPackage(userHandle.getIdentifier());
+                .getDefaultDialerPackage(userHandle);
         return new Intent(TelephonyManager.ACTION_SHOW_VOICEMAIL_NOTIFICATION)
                 .setPackage(dialerPackage);
     }
diff --git a/src/com/android/phone/NumberVerificationManager.java b/src/com/android/phone/NumberVerificationManager.java
index 9ec16f8..2298d40 100644
--- a/src/com/android/phone/NumberVerificationManager.java
+++ b/src/com/android/phone/NumberVerificationManager.java
@@ -135,7 +135,7 @@
                 }
 
                 // make sure at least one phone is registered for voice
-                if (phone.getServiceState().getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {
+                if (phone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE) {
                     isAnyPhoneVoiceRegistered = true;
                 }
                 // make sure at least one phone has room for an incoming call.
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 5d4d9b3..6f657b4 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -26,6 +26,7 @@
 import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.content.res.XmlResourceParser;
 import android.media.AudioManager;
 import android.net.ConnectivityManager;
@@ -66,9 +67,11 @@
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.dataconnection.DataConnectionReasons;
 import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataDisallowedReasonType;
+import com.android.internal.telephony.ims.ImsResolver;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.phone.settings.SettingsConstants;
 import com.android.phone.vvm.CarrierVvmPackageInstalledReceiver;
+import com.android.services.telephony.rcs.TelephonyRcsService;
 import com.android.services.telephony.sip.SipAccountRegistry;
 import com.android.services.telephony.sip.SipUtil;
 
@@ -146,6 +149,8 @@
     CallNotifier notifier;
     CallerInfoCache callerInfoCache;
     NotificationMgr notificationMgr;
+    ImsResolver mImsResolver;
+    TelephonyRcsService mTelephonyRcsService;
     public PhoneInterfaceManager phoneMgr;
     public ImsRcsController imsRcsController;
     CarrierConfigLoader configLoader;
@@ -300,8 +305,8 @@
         // Cache the "voice capable" flag.
         // This flag currently comes from a resource (which is
         // overrideable on a per-product basis):
-        sVoiceCapable =
-                getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);
+        sVoiceCapable = ((TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE))
+                .isVoiceCapable();
         // ...but this might eventually become a PackageManager "system
         // feature" instead, in which case we'd do something like:
         // sVoiceCapable =
@@ -317,6 +322,19 @@
             // Initialize the telephony framework
             PhoneFactory.makeDefaultPhones(this);
 
+            // Only bring up ImsResolver if the device supports having an IMS stack.
+            if (getPackageManager().hasSystemFeature(
+                    PackageManager.FEATURE_TELEPHONY_IMS)) {
+                // Get the package name of the default IMS implementation.
+                String defaultImsMmtelPackage = getResources().getString(
+                        R.string.config_ims_mmtel_package);
+                String defaultImsRcsPackage = getResources().getString(
+                        R.string.config_ims_rcs_package);
+                mImsResolver = new ImsResolver(this, defaultImsMmtelPackage,
+                        defaultImsRcsPackage, PhoneFactory.getPhones().length);
+                mImsResolver.initialize();
+            }
+
             // Start TelephonyDebugService After the default phone is created.
             Intent intent = new Intent(this, TelephonyDebugService.class);
             startService(intent);
@@ -356,6 +374,13 @@
 
             imsRcsController = ImsRcsController.init(this);
 
+            if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS)) {
+                mTelephonyRcsService = new TelephonyRcsService(this,
+                        PhoneFactory.getPhones().length);
+                mTelephonyRcsService.initialize();
+                imsRcsController.setRcsService(mTelephonyRcsService);
+            }
+
             configLoader = CarrierConfigLoader.init(this);
 
             // Create the CallNotifier singleton, which handles
@@ -387,7 +412,7 @@
             IntentFilter sipIntentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
             sipIntentFilter.addAction(SipManager.ACTION_SIP_SERVICE_UP);
             sipIntentFilter.addAction(SipManager.ACTION_SIP_CALL_OPTION_CHANGED);
-            sipIntentFilter.addAction(SipManager.ACTION_SIP_REMOVE_PHONE);
+            sipIntentFilter.addAction(SipManager.ACTION_SIP_REMOVE_PROFILE);
             registerReceiver(mSipReceiver, sipIntentFilter);
 
             mCarrierVvmPackageInstalledReceiver.register(this);
@@ -438,6 +463,10 @@
         return PhoneFactory.getPhone(SubscriptionManager.getPhoneId(subId));
     }
 
+    public ImsResolver getImsResolver() {
+        return mImsResolver;
+    }
+
     /* package */ CallManager getCallManager() {
         return mCM;
     }
@@ -447,7 +476,7 @@
     }
 
     public PersistableBundle getCarrierConfigForSubId(int subId) {
-        return configLoader.getConfigForSubId(subId, getOpPackageName());
+        return configLoader.getConfigForSubIdWithFeature(subId, getOpPackageName(), null);
     }
 
     private void registerSettingsObserver() {
@@ -642,7 +671,8 @@
                     if (TelephonyCapabilities.supportsEcm(phoneInEcm)) {
                         Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp.");
                         // Start Emergency Callback Mode service
-                        if (intent.getBooleanExtra("phoneinECMState", false)) {
+                        if (intent.getBooleanExtra(
+                                TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false)) {
                             context.startService(new Intent(context,
                                     EmergencyCallbackModeService.class));
                         } else {
@@ -688,7 +718,7 @@
             } else if (action.equals(SipManager.ACTION_SIP_SERVICE_UP)
                     || action.equals(SipManager.ACTION_SIP_CALL_OPTION_CHANGED)) {
                 sipAccountRegistry.setup(context);
-            } else if (action.equals(SipManager.ACTION_SIP_REMOVE_PHONE)) {
+            } else if (action.equals(SipManager.ACTION_SIP_REMOVE_PROFILE)) {
                 if (DBG) {
                     Log.d(LOG_TAG, "SIP_REMOVE_PHONE "
                             + intent.getStringExtra(SipManager.EXTRA_LOCAL_URI));
@@ -877,6 +907,20 @@
         pw.increaseIndent();
         mDataRoamingNotifLog.dump(fd, pw, args);
         pw.decreaseIndent();
+        pw.println("ImsResolver:");
+        pw.increaseIndent();
+        try {
+            if (mImsResolver != null) mImsResolver.dump(fd, pw, args);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        pw.decreaseIndent();
+        pw.println("RcsService:");
+        try {
+            if (mTelephonyRcsService != null) mTelephonyRcsService.dump(fd, pw, args);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
         pw.decreaseIndent();
         pw.println("------- End PhoneGlobals -------");
     }
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 296525d..05f7872 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -22,6 +22,7 @@
 import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
 
 import android.Manifest.permission;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
@@ -34,7 +35,6 @@
 import android.content.pm.ComponentInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.net.NetworkStats;
 import android.net.Uri;
 import android.os.AsyncResult;
 import android.os.Binder;
@@ -45,14 +45,15 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
+import android.os.ParcelFileDescriptor;
 import android.os.ParcelUuid;
 import android.os.PersistableBundle;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
 import android.os.ShellCallback;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.WorkSource;
@@ -60,17 +61,20 @@
 import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.provider.Telephony;
+import android.sysprop.TelephonyProperties;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.telephony.Annotation.ApnType;
+import android.telephony.CallForwardingInfo;
 import android.telephony.CarrierConfigManager;
 import android.telephony.CarrierRestrictionRules;
 import android.telephony.CellIdentity;
+import android.telephony.CellIdentityCdma;
+import android.telephony.CellIdentityGsm;
 import android.telephony.CellInfo;
 import android.telephony.CellInfoGsm;
 import android.telephony.CellInfoWcdma;
-import android.telephony.CellLocation;
 import android.telephony.ClientRequestStats;
 import android.telephony.ICellInfoCallback;
 import android.telephony.IccOpenLogicalChannelResponse;
@@ -82,7 +86,6 @@
 import android.telephony.PhoneNumberRange;
 import android.telephony.RadioAccessFamily;
 import android.telephony.RadioAccessSpecifier;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.SubscriptionInfo;
@@ -94,10 +97,8 @@
 import android.telephony.UiccSlotInfo;
 import android.telephony.UssdResponse;
 import android.telephony.VisualVoicemailSmsFilterSettings;
-import android.telephony.cdma.CdmaCellLocation;
 import android.telephony.data.ApnSetting;
 import android.telephony.emergency.EmergencyNumber;
-import android.telephony.gsm.GsmCellLocation;
 import android.telephony.ims.ImsException;
 import android.telephony.ims.ProvisioningManager;
 import android.telephony.ims.RegistrationManager;
@@ -110,30 +111,32 @@
 import android.telephony.ims.aidl.IImsRegistrationCallback;
 import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.feature.MmTelFeature;
+import android.telephony.ims.feature.RcsFeature;
 import android.telephony.ims.stub.ImsConfigImplBase;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Pair;
-import android.util.Slog;
 
 import com.android.ims.ImsManager;
 import com.android.ims.internal.IImsServiceFeatureCallback;
+import com.android.internal.telephony.CallForwardInfo;
 import com.android.internal.telephony.CallManager;
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.CarrierInfoManager;
 import com.android.internal.telephony.CarrierResolver;
 import com.android.internal.telephony.CellNetworkScanResult;
 import com.android.internal.telephony.CommandException;
+import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.DefaultPhoneNotifier;
 import com.android.internal.telephony.HalVersion;
+import com.android.internal.telephony.IBooleanConsumer;
 import com.android.internal.telephony.IIntegerConsumer;
 import com.android.internal.telephony.INumberVerificationCallback;
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.LocaleTracker;
-import com.android.internal.telephony.MccTable;
 import com.android.internal.telephony.NetworkScanRequestTracker;
 import com.android.internal.telephony.OperatorInfo;
 import com.android.internal.telephony.Phone;
@@ -158,6 +161,7 @@
 import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
 import com.android.internal.telephony.uicc.IccIoResult;
+import com.android.internal.telephony.uicc.IccRecords;
 import com.android.internal.telephony.uicc.IccUtils;
 import com.android.internal.telephony.uicc.SIMRecords;
 import com.android.internal.telephony.uicc.UiccCard;
@@ -165,6 +169,7 @@
 import com.android.internal.telephony.uicc.UiccController;
 import com.android.internal.telephony.uicc.UiccProfile;
 import com.android.internal.telephony.uicc.UiccSlot;
+import com.android.internal.telephony.util.LocaleUtils;
 import com.android.internal.telephony.util.VoicemailNotificationSettingsUtil;
 import com.android.internal.util.HexDump;
 import com.android.phone.settings.PickSmsSubscriptionActivity;
@@ -172,6 +177,7 @@
 import com.android.phone.vvm.RemoteVvmTaskManager;
 import com.android.phone.vvm.VisualVoicemailSettingsUtil;
 import com.android.phone.vvm.VisualVoicemailSmsFilterConfig;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -184,6 +190,7 @@
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
+import java.util.function.Consumer;
 
 /**
  * Implementation of the ITelephony interface.
@@ -265,6 +272,20 @@
     private static final int EVENT_SET_FORBIDDEN_PLMNS_DONE = 73;
     private static final int CMD_ERASE_MODEM_CONFIG = 74;
     private static final int EVENT_ERASE_MODEM_CONFIG_DONE = 75;
+    private static final int CMD_CHANGE_ICC_LOCK_PASSWORD = 76;
+    private static final int EVENT_CHANGE_ICC_LOCK_PASSWORD_DONE = 77;
+    private static final int CMD_SET_ICC_LOCK_ENABLED = 78;
+    private static final int EVENT_SET_ICC_LOCK_ENABLED_DONE = 79;
+    private static final int CMD_SET_SYSTEM_SELECTION_CHANNELS = 80;
+    private static final int EVENT_SET_SYSTEM_SELECTION_CHANNELS_DONE = 81;
+    private static final int CMD_GET_CALL_FORWARDING = 83;
+    private static final int EVENT_GET_CALL_FORWARDING_DONE = 84;
+    private static final int CMD_SET_CALL_FORWARDING = 85;
+    private static final int EVENT_SET_CALL_FORWARDING_DONE = 86;
+    private static final int CMD_GET_CALL_WAITING = 87;
+    private static final int EVENT_GET_CALL_WAITING_DONE = 88;
+    private static final int CMD_SET_CALL_WAITING = 89;
+    private static final int EVENT_SET_CALL_WAITING_DONE = 90;
 
     // Parameters of select command.
     private static final int SELECT_COMMAND = 0xA4;
@@ -272,15 +293,12 @@
     private static final int SELECT_P2 = 0;
     private static final int SELECT_P3 = 0x10;
 
-    private static final String DEFAULT_NETWORK_MODE_PROPERTY_NAME = "ro.telephony.default_network";
-    private static final String DEFAULT_DATA_ROAMING_PROPERTY_NAME = "ro.com.android.dataroaming";
-    private static final String DEFAULT_MOBILE_DATA_PROPERTY_NAME = "ro.com.android.mobiledata";
-
     /** The singleton instance. */
     private static PhoneInterfaceManager sInstance;
 
     private PhoneGlobals mApp;
     private CallManager mCM;
+    private ImsResolver mImsResolver;
     private UserManager mUserManager;
     private AppOpsManager mAppOps;
     private MainThreadHandler mMainThreadHandler;
@@ -802,6 +820,148 @@
                     getPhoneFromRequest(request).getAvailableNetworks(onCompleted);
                     break;
 
+                case CMD_GET_CALL_FORWARDING:
+                    request = (MainThreadRequest) msg.obj;
+                    onCompleted = obtainMessage(EVENT_GET_CALL_FORWARDING_DONE, request);
+                    int callForwardingReason = (Integer) request.argument;
+                    getPhoneFromRequest(request).getCallForwardingOption(
+                            callForwardingReason, onCompleted);
+                    break;
+
+                case EVENT_GET_CALL_FORWARDING_DONE:
+                    ar = (AsyncResult) msg.obj;
+                    request = (MainThreadRequest) ar.userObj;
+                    CallForwardingInfo callForwardingInfo = null;
+                    if (ar.exception == null && ar.result != null) {
+                        CallForwardInfo[] callForwardInfos = (CallForwardInfo[]) ar.result;
+                        for (CallForwardInfo callForwardInfo : callForwardInfos) {
+                            // Service Class is a bit mask per 3gpp 27.007. Search for
+                            // any service for voice call.
+                            if ((callForwardInfo.serviceClass
+                                    & CommandsInterface.SERVICE_CLASS_VOICE) > 0) {
+                                callForwardingInfo = new CallForwardingInfo(
+                                        callForwardInfo.serviceClass, callForwardInfo.reason,
+                                                callForwardInfo.number,
+                                                        callForwardInfo.timeSeconds);
+                                break;
+                            }
+                        }
+                        // Didn't find a call forward info for voice call.
+                        if (callForwardingInfo == null) {
+                            callForwardingInfo = new CallForwardingInfo(
+                                    CallForwardingInfo.STATUS_UNKNOWN_ERROR,
+                                            0 /* reason */, null /* number */, 0 /* timeout */);
+                        }
+                    } else {
+                        if (ar.result == null) {
+                            loge("EVENT_GET_CALL_FORWARDING_DONE: Empty response");
+                        }
+                        if (ar.exception != null) {
+                            loge("EVENT_GET_CALL_FORWARDING_DONE: Exception: " + ar.exception);
+                        }
+                        int errorCode = CallForwardingInfo.STATUS_UNKNOWN_ERROR;
+                        if (ar.exception instanceof CommandException) {
+                            CommandException.Error error =
+                                    ((CommandException) (ar.exception)).getCommandError();
+                            if (error == CommandException.Error.FDN_CHECK_FAILURE) {
+                                errorCode = CallForwardingInfo.STATUS_FDN_CHECK_FAILURE;
+                            } else if (error == CommandException.Error.REQUEST_NOT_SUPPORTED) {
+                                errorCode = CallForwardingInfo.STATUS_NOT_SUPPORTED;
+                            }
+                        }
+                        callForwardingInfo = new CallForwardingInfo(
+                                errorCode, 0 /* reason */, null /* number */, 0 /* timeout */);
+                    }
+                    request.result = callForwardingInfo;
+                    notifyRequester(request);
+                    break;
+
+                case CMD_SET_CALL_FORWARDING:
+                    request = (MainThreadRequest) msg.obj;
+                    onCompleted = obtainMessage(EVENT_SET_CALL_FORWARDING_DONE, request);
+                    CallForwardingInfo callForwardingInfoToSet =
+                            (CallForwardingInfo) request.argument;
+                    getPhoneFromRequest(request).setCallForwardingOption(
+                            callForwardingInfoToSet.getStatus(),
+                            callForwardingInfoToSet.getReason(),
+                            callForwardingInfoToSet.getNumber(),
+                            callForwardingInfoToSet.getTimeoutSeconds(), onCompleted);
+                    break;
+
+                case EVENT_SET_CALL_FORWARDING_DONE:
+                    ar = (AsyncResult) msg.obj;
+                    request = (MainThreadRequest) ar.userObj;
+                    if (ar.exception == null) {
+                        request.result = true;
+                    } else {
+                        request.result = false;
+                        loge("setCallForwarding exception: " + ar.exception);
+                    }
+                    notifyRequester(request);
+                    break;
+
+                case CMD_GET_CALL_WAITING:
+                    request = (MainThreadRequest) msg.obj;
+                    onCompleted = obtainMessage(EVENT_GET_CALL_WAITING_DONE, request);
+                    getPhoneFromRequest(request).getCallWaiting(onCompleted);
+                    break;
+
+                case EVENT_GET_CALL_WAITING_DONE:
+                    ar = (AsyncResult) msg.obj;
+                    request = (MainThreadRequest) ar.userObj;
+                    int callForwardingStatus = TelephonyManager.CALL_WAITING_STATUS_UNKNOWN_ERROR;
+                    if (ar.exception == null && ar.result != null) {
+                        int[] callForwardResults = (int[]) ar.result;
+                        // Service Class is a bit mask per 3gpp 27.007.
+                        // Search for any service for voice call.
+                        if (callForwardResults.length > 1
+                                && ((callForwardResults[1]
+                                        & CommandsInterface.SERVICE_CLASS_VOICE) > 0)) {
+                            callForwardingStatus = callForwardResults[0] == 0
+                                    ? TelephonyManager.CALL_WAITING_STATUS_INACTIVE
+                                            : TelephonyManager.CALL_WAITING_STATUS_ACTIVE;
+                        } else {
+                            callForwardingStatus = TelephonyManager.CALL_WAITING_STATUS_INACTIVE;
+                        }
+                    } else {
+                        if (ar.result == null) {
+                            loge("EVENT_GET_CALL_WAITING_DONE: Empty response");
+                        }
+                        if (ar.exception != null) {
+                            loge("EVENT_GET_CALL_WAITING_DONE: Exception: " + ar.exception);
+                        }
+                        if (ar.exception instanceof CommandException) {
+                            CommandException.Error error =
+                                    ((CommandException) (ar.exception)).getCommandError();
+                            if (error == CommandException.Error.REQUEST_NOT_SUPPORTED) {
+                                callForwardingStatus =
+                                        TelephonyManager.CALL_WAITING_STATUS_NOT_SUPPORTED;
+                            }
+                        }
+                    }
+                    request.result = callForwardingStatus;
+                    notifyRequester(request);
+                    break;
+
+                case CMD_SET_CALL_WAITING:
+                    request = (MainThreadRequest) msg.obj;
+                    onCompleted = obtainMessage(EVENT_SET_CALL_WAITING_DONE, request);
+                    boolean isEnable = (Boolean) request.argument;
+                    getPhoneFromRequest(request).setCallWaiting(isEnable, onCompleted);
+                    break;
+
+                case EVENT_SET_CALL_WAITING_DONE:
+                    ar = (AsyncResult) msg.obj;
+                    request = (MainThreadRequest) ar.userObj;
+                    if (ar.exception == null) {
+                        request.result = true;
+                    } else {
+                        request.result = false;
+                        loge("setCallWaiting exception: " + ar.exception);
+                    }
+                    notifyRequester(request);
+                    break;
+
                 case EVENT_PERFORM_NETWORK_SCAN_DONE:
                     ar = (AsyncResult) msg.obj;
                     request = (MainThreadRequest) ar.userObj;
@@ -861,14 +1021,47 @@
                     onCompleted = obtainMessage(EVENT_GET_MODEM_ACTIVITY_INFO_DONE, request);
                     if (defaultPhone != null) {
                         defaultPhone.getModemActivityInfo(onCompleted, request.workSource);
+                    } else {
+                        ResultReceiver result = (ResultReceiver) request.argument;
+                        Bundle bundle = new Bundle();
+                        bundle.putParcelable(TelephonyManager.MODEM_ACTIVITY_RESULT_KEY,
+                                new ModemActivityInfo(0, 0, 0, new int[0], 0));
+                        result.send(0, bundle);
                     }
                     break;
 
                 case EVENT_GET_MODEM_ACTIVITY_INFO_DONE:
                     ar = (AsyncResult) msg.obj;
                     request = (MainThreadRequest) ar.userObj;
+                    ResultReceiver result = (ResultReceiver) request.argument;
+
+                    ModemActivityInfo ret = new ModemActivityInfo(0, 0, 0, new int[0], 0);
                     if (ar.exception == null && ar.result != null) {
-                        request.result = ar.result;
+                        // Update the last modem activity info and the result of the request.
+                        ModemActivityInfo info = (ModemActivityInfo) ar.result;
+                        if (isModemActivityInfoValid(info)) {
+                            int[] mergedTxTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
+                            int[] txTimeMs = info.getTransmitTimeMillis();
+                            int[] lastModemTxTimeMs = mLastModemActivityInfo
+                                    .getTransmitTimeMillis();
+                            for (int i = 0; i < mergedTxTimeMs.length; i++) {
+                                mergedTxTimeMs[i] = txTimeMs[i] + lastModemTxTimeMs[i];
+                            }
+                            mLastModemActivityInfo.setTimestamp(info.getTimestamp());
+                            mLastModemActivityInfo.setSleepTimeMillis(info.getSleepTimeMillis()
+                                    + mLastModemActivityInfo.getSleepTimeMillis());
+                            mLastModemActivityInfo.setIdleTimeMillis(info.getIdleTimeMillis()
+                                    + mLastModemActivityInfo.getIdleTimeMillis());
+                            mLastModemActivityInfo.setTransmitTimeMillis(mergedTxTimeMs);
+                            mLastModemActivityInfo.setReceiveTimeMillis(
+                                    info.getReceiveTimeMillis()
+                                            + mLastModemActivityInfo.getReceiveTimeMillis());
+                        }
+                        ret = new ModemActivityInfo(mLastModemActivityInfo.getTimestamp(),
+                                mLastModemActivityInfo.getSleepTimeMillis(),
+                                mLastModemActivityInfo.getIdleTimeMillis(),
+                                mLastModemActivityInfo.getTransmitTimeMillis(),
+                                mLastModemActivityInfo.getReceiveTimeMillis());
                     } else {
                         if (ar.result == null) {
                             loge("queryModemActivityInfo: Empty response");
@@ -879,10 +1072,9 @@
                             loge("queryModemActivityInfo: Unknown exception");
                         }
                     }
-                    // Result cannot be null. Return ModemActivityInfo with all fields set to 0.
-                    if (request.result == null) {
-                        request.result = new ModemActivityInfo(0, 0, 0, null, 0, 0);
-                    }
+                    Bundle bundle = new Bundle();
+                    bundle.putParcelable(TelephonyManager.MODEM_ACTIVITY_RESULT_KEY, ret);
+                    result.send(0, bundle);
                     notifyRequester(request);
                     break;
 
@@ -1105,7 +1297,7 @@
                     request = (MainThreadRequest) msg.obj;
                     WorkSource ws = (WorkSource) request.argument;
                     Phone phone = getPhoneFromRequest(request);
-                    phone.getCellLocation(ws, obtainMessage(EVENT_GET_CELL_LOCATION_DONE, request));
+                    phone.getCellIdentity(ws, obtainMessage(EVENT_GET_CELL_LOCATION_DONE, request));
                     break;
                 case EVENT_GET_CELL_LOCATION_DONE:
                     ar = (AsyncResult) msg.obj;
@@ -1115,7 +1307,7 @@
                     } else {
                         phone = getPhoneFromRequest(request);
                         request.result = (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA)
-                                ? new CdmaCellLocation() : new GsmCellLocation();
+                                ? new CellIdentityCdma() : new CellIdentityGsm();
                     }
 
                     synchronized (request) {
@@ -1180,6 +1372,23 @@
                     }
                     notifyRequester(request);
                     break;
+                case CMD_SET_SYSTEM_SELECTION_CHANNELS: {
+                    request = (MainThreadRequest) msg.obj;
+                    onCompleted = obtainMessage(EVENT_SET_SYSTEM_SELECTION_CHANNELS_DONE, request);
+                    Pair<List<RadioAccessSpecifier>, Consumer<Boolean>> args =
+                            (Pair<List<RadioAccessSpecifier>, Consumer<Boolean>>) request.argument;
+                    request.phone.setSystemSelectionChannels(args.first, onCompleted);
+                    break;
+                }
+                case EVENT_SET_SYSTEM_SELECTION_CHANNELS_DONE: {
+                    ar = (AsyncResult) msg.obj;
+                    request = (MainThreadRequest) ar.userObj;
+                    Pair<List<RadioAccessSpecifier>, Consumer<Boolean>> args =
+                            (Pair<List<RadioAccessSpecifier>, Consumer<Boolean>>) request.argument;
+                    args.second.accept(ar.exception == null);
+                    notifyRequester(request);
+                    break;
+                }
                 case EVENT_SET_FORBIDDEN_PLMNS_DONE:
                     ar = (AsyncResult) msg.obj;
                     request = (MainThreadRequest) ar.userObj;
@@ -1232,6 +1441,43 @@
                 case EVENT_ERASE_MODEM_CONFIG_DONE:
                     handleNullReturnEvent(msg, "eraseModemConfig");
                     break;
+
+                case CMD_CHANGE_ICC_LOCK_PASSWORD:
+                    request = (MainThreadRequest) msg.obj;
+                    onCompleted = obtainMessage(EVENT_CHANGE_ICC_LOCK_PASSWORD_DONE, request);
+                    Pair<String, String> changed = (Pair<String, String>) request.argument;
+                    getPhoneFromRequest(request).getIccCard().changeIccLockPassword(
+                            changed.first, changed.second, onCompleted);
+                    break;
+                case EVENT_CHANGE_ICC_LOCK_PASSWORD_DONE:
+                    ar = (AsyncResult) msg.obj;
+                    request = (MainThreadRequest) ar.userObj;
+                    if (ar.exception == null) {
+                        request.result = TelephonyManager.CHANGE_ICC_LOCK_SUCCESS;
+                    } else {
+                        request.result = msg.arg1;
+                    }
+                    notifyRequester(request);
+                    break;
+
+                case CMD_SET_ICC_LOCK_ENABLED:
+                    request = (MainThreadRequest) msg.obj;
+                    onCompleted = obtainMessage(EVENT_SET_ICC_LOCK_ENABLED_DONE, request);
+                    Pair<Boolean, String> enabled = (Pair<Boolean, String>) request.argument;
+                    getPhoneFromRequest(request).getIccCard().setIccLockEnabled(
+                            enabled.first, enabled.second, onCompleted);
+                    break;
+                case EVENT_SET_ICC_LOCK_ENABLED_DONE:
+                    ar = (AsyncResult) msg.obj;
+                    request = (MainThreadRequest) ar.userObj;
+                    if (ar.exception == null) {
+                        request.result = TelephonyManager.CHANGE_ICC_LOCK_SUCCESS;
+                    } else {
+                        request.result = msg.arg1;
+                    }
+                    notifyRequester(request);
+                    break;
+
                 default:
                     Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
                     break;
@@ -1393,6 +1639,7 @@
     private PhoneInterfaceManager(PhoneGlobals app) {
         mApp = app;
         mCM = PhoneGlobals.getInstance().mCM;
+        mImsResolver = PhoneGlobals.getInstance().getImsResolver();
         mUserManager = (UserManager) app.getSystemService(Context.USER_SERVICE);
         mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
         mMainThreadHandler = new MainThreadHandler();
@@ -1454,6 +1701,16 @@
         }
     }
 
+    private boolean isImsAvailableOnDevice() {
+        PackageManager pm = getDefaultPhone().getContext().getPackageManager();
+        if (pm == null) {
+            // For some reason package manger is not available.. This will fail internally anyway,
+            // so do not throw error and allow.
+            return true;
+        }
+        return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS, 0);
+    }
+
     public void dial(String number) {
         dialForSubscriber(getPreferredVoiceSubscription(), number);
     }
@@ -1530,29 +1787,16 @@
         }
     }
 
-    public boolean supplyPin(String pin) {
-        return supplyPinForSubscriber(getDefaultSubscription(), pin);
-    }
-
     public boolean supplyPinForSubscriber(int subId, String pin) {
         int [] resultArray = supplyPinReportResultForSubscriber(subId, pin);
         return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
     }
 
-    public boolean supplyPuk(String puk, String pin) {
-        return supplyPukForSubscriber(getDefaultSubscription(), puk, pin);
-    }
-
     public boolean supplyPukForSubscriber(int subId, String puk, String pin) {
         int [] resultArray = supplyPukReportResultForSubscriber(subId, puk, pin);
         return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
     }
 
-    /** {@hide} */
-    public int[] supplyPinReportResult(String pin) {
-        return supplyPinReportResultForSubscriber(getDefaultSubscription(), pin);
-    }
-
     public int[] supplyPinReportResultForSubscriber(int subId, String pin) {
         enforceModifyPermission();
 
@@ -1566,11 +1810,6 @@
         }
     }
 
-    /** {@hide} */
-    public int[] supplyPukReportResult(String puk, String pin) {
-        return supplyPukReportResultForSubscriber(getDefaultSubscription(), puk, pin);
-    }
-
     public int[] supplyPukReportResultForSubscriber(int subId, String puk, String pin) {
         enforceModifyPermission();
 
@@ -1703,15 +1942,29 @@
         }
     }
 
+    @Deprecated
     @Override
     public boolean isRadioOn(String callingPackage) {
-        return isRadioOnForSubscriber(getDefaultSubscription(), callingPackage);
+        return isRadioOnWithFeature(callingPackage, null);
     }
 
     @Override
+    public boolean isRadioOnWithFeature(String callingPackage, String callingFeatureId) {
+        return isRadioOnForSubscriberWithFeature(getDefaultSubscription(), callingPackage,
+                callingFeatureId);
+    }
+
+    @Deprecated
+    @Override
     public boolean isRadioOnForSubscriber(int subId, String callingPackage) {
+        return isRadioOnForSubscriberWithFeature(subId, callingPackage, null);
+    }
+
+    @Override
+    public boolean isRadioOnForSubscriberWithFeature(int subId, String callingPackage,
+            String callingFeatureId) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, "isRadioOnForSubscriber")) {
+                mApp, subId, callingPackage, callingFeatureId, "isRadioOnForSubscriber")) {
             return false;
         }
 
@@ -1998,7 +2251,7 @@
     }
 
     @Override
-    public Bundle getCellLocation(String callingPackage) {
+    public CellIdentity getCellLocation(String callingPackage, String callingFeatureId) {
         mApp.getSystemService(AppOpsManager.class)
                 .checkPackage(Binder.getCallingUid(), callingPackage);
 
@@ -2006,6 +2259,7 @@
                 LocationAccessPolicy.checkLocationPermission(mApp,
                         new LocationAccessPolicy.LocationPermissionQuery.Builder()
                                 .setCallingPackage(callingPackage)
+                                .setCallingFeatureId(callingFeatureId)
                                 .setCallingPid(Binder.getCallingPid())
                                 .setCallingUid(Binder.getCallingUid())
                                 .setMethod("getCellLocation")
@@ -2015,33 +2269,23 @@
             case DENIED_HARD:
                 throw new SecurityException("Not allowed to access cell location");
             case DENIED_SOFT:
-                return new Bundle();
+                return (getDefaultPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA)
+                        ? new CellIdentityCdma() : new CellIdentityGsm();
         }
 
         WorkSource workSource = getWorkSource(Binder.getCallingUid());
         final long identity = Binder.clearCallingIdentity();
         try {
             if (DBG_LOC) log("getCellLocation: is active user");
-            Bundle data = new Bundle();
             int subId = mSubscriptionController.getDefaultDataSubId();
-            CellLocation cl = (CellLocation) sendRequest(CMD_GET_CELL_LOCATION, workSource, subId);
-            cl.fillInNotifierBundle(data);
-            return data;
+            return (CellIdentity) sendRequest(CMD_GET_CELL_LOCATION, workSource, subId);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
     }
 
     @Override
-    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 "";
-            }
-        }
-
+    public String getNetworkCountryIsoForPhone(int phoneId) {
         // 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();
@@ -2054,7 +2298,8 @@
             // Todo: fix this when we can get the actual cellular network info when the device
             // is on IWLAN.
             if (TelephonyManager.NETWORK_TYPE_IWLAN
-                    == getVoiceNetworkTypeForSubscriber(subId, mApp.getPackageName())) {
+                    == getVoiceNetworkTypeForSubscriber(subId, mApp.getPackageName(),
+                    null)) {
                 return "";
             }
             Phone phone = PhoneFactory.getPhone(phoneId);
@@ -2141,7 +2386,8 @@
 
     @Override
     @SuppressWarnings("unchecked")
-    public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage) {
+    public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage,
+            String callingFeatureId) {
         final int targetSdk = getTargetSdk(callingPackage);
         if (targetSdk >= android.os.Build.VERSION_CODES.Q) {
             throw new SecurityException(
@@ -2155,7 +2401,7 @@
 
         if (DBG_LOC) log("getNeighboringCellInfo: is active user");
 
-        List<CellInfo> info = getAllCellInfo(callingPackage);
+        List<CellInfo> info = getAllCellInfo(callingPackage, callingFeatureId);
         if (info == null) return null;
 
         List<NeighboringCellInfo> neighbors = new ArrayList<NeighboringCellInfo>();
@@ -2179,7 +2425,7 @@
     }
 
     @Override
-    public List<CellInfo> getAllCellInfo(String callingPackage) {
+    public List<CellInfo> getAllCellInfo(String callingPackage, String callingFeatureId) {
         mApp.getSystemService(AppOpsManager.class)
                 .checkPackage(Binder.getCallingUid(), callingPackage);
 
@@ -2187,6 +2433,7 @@
                 LocationAccessPolicy.checkLocationPermission(mApp,
                         new LocationAccessPolicy.LocationPermissionQuery.Builder()
                                 .setCallingPackage(callingPackage)
+                                .setCallingFeatureId(callingFeatureId)
                                 .setCallingPid(Binder.getCallingPid())
                                 .setCallingUid(Binder.getCallingUid())
                                 .setMethod("getAllCellInfo")
@@ -2222,20 +2469,21 @@
     }
 
     @Override
-    public void requestCellInfoUpdate(int subId, ICellInfoCallback cb, String callingPackage) {
-        requestCellInfoUpdateInternal(
-                subId, cb, callingPackage, getWorkSource(Binder.getCallingUid()));
+    public void requestCellInfoUpdate(int subId, ICellInfoCallback cb, String callingPackage,
+            String callingFeatureId) {
+        requestCellInfoUpdateInternal(subId, cb, callingPackage, callingFeatureId,
+                getWorkSource(Binder.getCallingUid()));
     }
 
     @Override
-    public void requestCellInfoUpdateWithWorkSource(
-            int subId, ICellInfoCallback cb, String callingPackage, WorkSource workSource) {
+    public void requestCellInfoUpdateWithWorkSource(int subId, ICellInfoCallback cb,
+            String callingPackage, String callingFeatureId, WorkSource workSource) {
         enforceModifyPermission();
-        requestCellInfoUpdateInternal(subId, cb, callingPackage, workSource);
+        requestCellInfoUpdateInternal(subId, cb, callingPackage, callingFeatureId, workSource);
     }
 
-    private void requestCellInfoUpdateInternal(
-            int subId, ICellInfoCallback cb, String callingPackage, WorkSource workSource) {
+    private void requestCellInfoUpdateInternal(int subId, ICellInfoCallback cb,
+            String callingPackage, String callingFeatureId, WorkSource workSource) {
         mApp.getSystemService(AppOpsManager.class)
                 .checkPackage(Binder.getCallingUid(), callingPackage);
 
@@ -2243,6 +2491,7 @@
                 LocationAccessPolicy.checkLocationPermission(mApp,
                         new LocationAccessPolicy.LocationPermissionQuery.Builder()
                                 .setCallingPackage(callingPackage)
+                                .setCallingFeatureId(callingFeatureId)
                                 .setCallingPid(Binder.getCallingPid())
                                 .setCallingUid(Binder.getCallingUid())
                                 .setMethod("requestCellInfoUpdate")
@@ -2281,14 +2530,14 @@
     }
 
     @Override
-    public String getImeiForSlot(int slotIndex, String callingPackage) {
+    public String getImeiForSlot(int slotIndex, String callingPackage, String callingFeatureId) {
         Phone phone = PhoneFactory.getPhone(slotIndex);
         if (phone == null) {
             return null;
         }
         int subId = phone.getSubId();
         if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mApp, subId,
-                callingPackage, "getImeiForSlot")) {
+                callingPackage, callingFeatureId, "getImeiForSlot")) {
             return null;
         }
 
@@ -2312,7 +2561,7 @@
     }
 
     @Override
-    public String getMeidForSlot(int slotIndex, String callingPackage) {
+    public String getMeidForSlot(int slotIndex, String callingPackage, String callingFeatureId) {
         Phone phone = PhoneFactory.getPhone(slotIndex);
         if (phone == null) {
             return null;
@@ -2320,7 +2569,7 @@
 
         int subId = phone.getSubId();
         if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mApp, subId,
-                callingPackage, "getMeidForSlot")) {
+                callingPackage, callingFeatureId, "getMeidForSlot")) {
             return null;
         }
 
@@ -2344,14 +2593,16 @@
     }
 
     @Override
-    public String getDeviceSoftwareVersionForSlot(int slotIndex, String callingPackage) {
+    public String getDeviceSoftwareVersionForSlot(int slotIndex, String callingPackage,
+            String callingFeatureId) {
         Phone phone = PhoneFactory.getPhone(slotIndex);
         if (phone == null) {
             return null;
         }
         int subId = phone.getSubId();
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, "getDeviceSoftwareVersionForSlot")) {
+                mApp, subId, callingPackage, callingFeatureId,
+                "getDeviceSoftwareVersionForSlot")) {
             return null;
         }
 
@@ -2438,6 +2689,17 @@
         mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
     }
 
+    /**
+     * Make sure the caller is system.
+     *
+     * @throws SecurityException if the caller is not system.
+     */
+    private void enforceSystemCaller() {
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+            throw new SecurityException("Caller must be system");
+        }
+    }
+
     private void enforceActiveEmergencySessionPermission() {
         mApp.enforceCallingOrSelfPermission(
                 android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION, null);
@@ -2500,14 +2762,17 @@
      * Returns the CDMA ERI icon index to display
      */
     @Override
-    public int getCdmaEriIconIndex(String callingPackage) {
-        return getCdmaEriIconIndexForSubscriber(getDefaultSubscription(), callingPackage);
+    public int getCdmaEriIconIndex(String callingPackage, String callingFeatureId) {
+        return getCdmaEriIconIndexForSubscriber(getDefaultSubscription(), callingPackage,
+                callingFeatureId);
     }
 
     @Override
-    public int getCdmaEriIconIndexForSubscriber(int subId, String callingPackage) {
+    public int getCdmaEriIconIndexForSubscriber(int subId, String callingPackage,
+            String callingFeatureId) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, "getCdmaEriIconIndexForSubscriber")) {
+                mApp, subId, callingPackage, callingFeatureId,
+                "getCdmaEriIconIndexForSubscriber")) {
             return -1;
         }
 
@@ -2530,14 +2795,17 @@
      * 1 - FLASHING
      */
     @Override
-    public int getCdmaEriIconMode(String callingPackage) {
-        return getCdmaEriIconModeForSubscriber(getDefaultSubscription(), callingPackage);
+    public int getCdmaEriIconMode(String callingPackage, String callingFeatureId) {
+        return getCdmaEriIconModeForSubscriber(getDefaultSubscription(), callingPackage,
+                callingFeatureId);
     }
 
     @Override
-    public int getCdmaEriIconModeForSubscriber(int subId, String callingPackage) {
+    public int getCdmaEriIconModeForSubscriber(int subId, String callingPackage,
+            String callingFeatureId) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, "getCdmaEriIconModeForSubscriber")) {
+                mApp, subId, callingPackage, callingFeatureId,
+                "getCdmaEriIconModeForSubscriber")) {
             return -1;
         }
 
@@ -2558,14 +2826,17 @@
      * Returns the CDMA ERI text,
      */
     @Override
-    public String getCdmaEriText(String callingPackage) {
-        return getCdmaEriTextForSubscriber(getDefaultSubscription(), callingPackage);
+    public String getCdmaEriText(String callingPackage, String callingFeatureId) {
+        return getCdmaEriTextForSubscriber(getDefaultSubscription(), callingPackage,
+                callingFeatureId);
     }
 
     @Override
-    public String getCdmaEriTextForSubscriber(int subId, String callingPackage) {
+    public String getCdmaEriTextForSubscriber(int subId, String callingPackage,
+            String callingFeatureId) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, "getCdmaEriIconTextForSubscriber")) {
+                mApp, subId, callingPackage, callingFeatureId,
+                "getCdmaEriIconTextForSubscriber")) {
             return null;
         }
 
@@ -2666,7 +2937,8 @@
      */
     @Override
     public boolean setVoiceMailNumber(int subId, String alphaTag, String number) {
-        TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(subId, "setVoiceMailNumber");
+        TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(
+                mApp, subId, "setVoiceMailNumber");
 
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -2700,10 +2972,12 @@
     }
 
     @Override
-    public String getVisualVoicemailPackageName(String callingPackage, int subId) {
+    public String getVisualVoicemailPackageName(String callingPackage, String callingFeatureId,
+            int subId) {
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, "getVisualVoicemailPackageName")) {
+                mApp, subId, callingPackage, callingFeatureId,
+                "getVisualVoicemailPackageName")) {
             return null;
         }
 
@@ -2770,14 +3044,15 @@
     }
 
     @Override
-    public void sendVisualVoicemailSmsForSubscriber(String callingPackage, int subId,
-            String number, int port, String text, PendingIntent sentIntent) {
+    public void sendVisualVoicemailSmsForSubscriber(String callingPackage,
+            String callingAttributionTag, int subId, String number, int port, String text,
+            PendingIntent sentIntent) {
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
         enforceVisualVoicemailPackage(callingPackage, subId);
         enforceSendSmsPermission();
         SmsController smsController = PhoneFactory.getSmsController();
-        smsController.sendVisualVoicemailSmsForSubscriber(callingPackage, subId, number, port, text,
-                sentIntent);
+        smsController.sendVisualVoicemailSmsForSubscriber(callingPackage, callingAttributionTag,
+                subId, number, port, text, sentIntent);
     }
 
     /**
@@ -2866,9 +3141,11 @@
      * Returns the unread count of voicemails for a subId
      */
     @Override
-    public int getVoiceMessageCountForSubscriber(int subId, String callingPackage) {
+    public int getVoiceMessageCountForSubscriber(int subId, String callingPackage,
+            String callingFeatureId) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, "getVoiceMessageCountForSubscriber")) {
+                mApp, subId, callingPackage, callingFeatureId,
+                "getVoiceMessageCountForSubscriber")) {
             return 0;
         }
         final long identity = Binder.clearCallingIdentity();
@@ -2911,7 +3188,7 @@
         TelecomManager tm = defaultPhone.getContext().getSystemService(TelecomManager.class);
         String defaultDialer = tm.getDefaultDialerPackage();
         if (!TextUtils.equals(callingPackage, defaultDialer)) {
-            TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(
+            TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mApp,
                     getDefaultSubscription(), "sendDialerSpecialCode");
         }
 
@@ -2925,11 +3202,18 @@
 
     @Override
     public int getNetworkSelectionMode(int subId) {
-        if (!isActiveSubscription(subId)) {
-            return TelephonyManager.NETWORK_SELECTION_MODE_UNKNOWN;
+        TelephonyPermissions
+                    .enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                    mApp, subId, "getNetworkSelectionMode");
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            if (!isActiveSubscription(subId)) {
+                return TelephonyManager.NETWORK_SELECTION_MODE_UNKNOWN;
+            }
+            return (int) sendRequest(CMD_GET_NETWORK_SELECTION_MODE, null /* argument */, subId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
         }
-
-        return (int) sendRequest(CMD_GET_NETWORK_SELECTION_MODE, null /* argument */, subId);
     }
 
     @Override
@@ -2948,10 +3232,17 @@
         return false;
     }
 
+    /**
+     * Requires carrier privileges or READ_PRECISE_PHONE_STATE permission.
+     * @param subId The subscription to use to check the configuration.
+     * @param c The callback that will be used to send the result.
+     */
     @Override
     public void registerImsRegistrationCallback(int subId, IImsRegistrationCallback c)
             throws RemoteException {
-        enforceReadPrivilegedPermission("registerImsRegistrationCallback");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "registerImsRegistrationCallback");
+
         if (!ImsManager.isImsSupportedOnDevice(mApp)) {
             throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
                     "IMS not available on device.");
@@ -2968,9 +3259,15 @@
         }
     }
 
+    /**
+     * Requires carrier privileges or READ_PRECISE_PHONE_STATE permission.
+     * @param subId The subscription to use to check the configuration.
+     * @param c The callback that will be used to send the result.
+     */
     @Override
     public void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback c) {
-        enforceReadPrivilegedPermission("unregisterImsRegistrationCallback");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "unregisterImsRegistrationCallback");
         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
             throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
         }
@@ -3026,7 +3323,8 @@
      */
     @Override
     public void getImsMmTelRegistrationTransportType(int subId, IIntegerConsumer consumer) {
-        enforceReadPrivilegedPermission("getImsMmTelRegistrationTransportType");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "getImsMmTelRegistrationTransportType");
         if (!ImsManager.isImsSupportedOnDevice(mApp)) {
             throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
                     "IMS not available on device.");
@@ -3057,10 +3355,16 @@
         }
     }
 
+    /**
+     * Requires carrier privileges or READ_PRECISE_PHONE_STATE permission.
+     * @param subId The subscription to use to check the configuration.
+     * @param c The callback that will be used to send the result.
+     */
     @Override
     public void registerMmTelCapabilityCallback(int subId, IImsCapabilityCallback c)
             throws RemoteException {
-        enforceReadPrivilegedPermission("registerMmTelCapabilityCallback");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "registerMmTelCapabilityCallback");
         if (!ImsManager.isImsSupportedOnDevice(mApp)) {
             throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
                     "IMS not available on device.");
@@ -3077,9 +3381,15 @@
         }
     }
 
+    /**
+     * Requires carrier privileges or READ_PRECISE_PHONE_STATE permission.
+     * @param subId The subscription to use to check the configuration.
+     * @param c The callback that will be used to send the result.
+     */
     @Override
     public void unregisterMmTelCapabilityCallback(int subId, IImsCapabilityCallback c) {
-        enforceReadPrivilegedPermission("unregisterMmTelCapabilityCallback");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "unregisterMmTelCapabilityCallback");
         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
             throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
         }
@@ -3169,9 +3479,15 @@
         }
     }
 
+    /**
+     * Requires carrier privileges or READ_PRECISE_PHONE_STATE permission.
+     * @param subId The subscription to use to check the configuration.
+     */
     @Override
     public boolean isAdvancedCallingSettingEnabled(int subId) {
-        enforceReadPrivilegedPermission("enforceReadPrivilegedPermission");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "isAdvancedCallingSettingEnabled");
+
         // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
         final long token = Binder.clearCallingIdentity();
         try {
@@ -3200,9 +3516,14 @@
         }
     }
 
+    /**
+     * Requires carrier privileges or READ_PRECISE_PHONE_STATE permission.
+     * @param subId The subscription to use to check the configuration.
+     */
     @Override
     public boolean isVtSettingEnabled(int subId) {
-        enforceReadPrivilegedPermission("isVtSettingEnabled");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "isVtSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -3229,9 +3550,14 @@
         }
     }
 
+    /**
+     * Requires carrier privileges or READ_PRECISE_PHONE_STATE permission.
+     * @param subId The subscription to use to check the configuration.
+     */
     @Override
     public boolean isVoWiFiSettingEnabled(int subId) {
-        enforceReadPrivilegedPermission("isVoWiFiSettingEnabled");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "isVoWiFiSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -3259,9 +3585,14 @@
         }
     }
 
+    /**
+     * Requires carrier privileges or READ_PRECISE_PHONE_STATE permission.
+     * @param subId The subscription to use to check the configuration.
+     */
     @Override
     public boolean isVoWiFiRoamingSettingEnabled(int subId) {
-        enforceReadPrivilegedPermission("isVoWiFiRoamingSettingEnabled");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "isVoWiFiRoamingSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -3306,9 +3637,14 @@
         }
     }
 
+    /**
+     * Requires carrier privileges or READ_PRECISE_PHONE_STATE permission.
+     * @param subId The subscription to use to check the configuration.
+     */
     @Override
     public int getVoWiFiModeSetting(int subId) {
-        enforceReadPrivilegedPermission("getVoWiFiModeSetting");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "getVoWiFiModeSetting");
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -3383,9 +3719,14 @@
         }
     }
 
+    /**
+     * Requires carrier privileges or READ_PRECISE_PHONE_STATE permission.
+     * @param subId The subscription to use to check the configuration.
+     */
     @Override
     public boolean isTtyOverVolteEnabled(int subId) {
-        enforceReadPrivilegedPermission("isTtyOverVolteEnabled");
+        TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "isTtyOverVolteEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -3403,6 +3744,10 @@
         enforceReadPrivilegedPermission("registerImsProvisioningChangedCallback");
         final long identity = Binder.clearCallingIdentity();
         try {
+            if (!isImsAvailableOnDevice()) {
+                throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+                        "IMS not available on device.");
+            }
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
             ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
                     .addProvisioningCallbackForSubscription(callback, subId);
@@ -3434,6 +3779,91 @@
         }
     }
 
+
+    private void checkModifyPhoneStatePermission(int subId, String message) {
+        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp, subId,
+                message);
+    }
+
+    private boolean isImsProvisioningRequired(int subId, int capability,
+            boolean isMmtelCapability) {
+        Phone phone = getPhone(subId);
+        if (phone == null) {
+            loge("phone instance null for subid " + subId);
+            return false;
+        }
+        if (isMmtelCapability) {
+            if (!doesImsCapabilityRequireProvisioning(phone.getContext(), subId, capability)) {
+                return false;
+            }
+        } else {
+            if (!doesRcsCapabilityRequireProvisioning(phone.getContext(), subId, capability)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public void setRcsProvisioningStatusForCapability(int subId, int capability,
+            boolean isProvisioned) {
+        checkModifyPhoneStatePermission(subId, "setRcsProvisioningStatusForCapability");
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
+            if (!isImsProvisioningRequired(subId, capability, false)) {
+                return;
+            }
+
+            // this capability requires provisioning, route to the correct API.
+            ImsManager ims = ImsManager.getInstance(mApp, getSlotIndex(subId));
+            switch (capability) {
+                case RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_OPTIONS_UCE:
+                case RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE:
+                    ims.setEabProvisioned(isProvisioned);
+                    break;
+                default: {
+                    throw new IllegalArgumentException("Tried to set provisioning for "
+                            + "rcs capability '" + capability + "', which does not require "
+                            + "provisioning.");
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+
+    }
+
+
+    @Override
+    public boolean getRcsProvisioningStatusForCapability(int subId, int capability) {
+        enforceReadPrivilegedPermission("getRcsProvisioningStatusForCapability");
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
+            if (!isImsProvisioningRequired(subId, capability, false)) {
+                return true;
+            }
+
+            ImsManager ims = ImsManager.getInstance(mApp, getSlotIndex(subId));
+            switch (capability) {
+                case RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_OPTIONS_UCE:
+                case RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE:
+                    return ims.isEabProvisionedOnDevice();
+
+                default: {
+                    throw new IllegalArgumentException("Tried to get rcs provisioning for "
+                            + "capability '" + capability + "', which does not require "
+                            + "provisioning.");
+                }
+            }
+
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     @Override
     public void setImsProvisioningStatusForCapability(int subId, int capability, int tech,
             boolean isProvisioned) {
@@ -3441,18 +3871,11 @@
                 && tech != ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
             throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid");
         }
-        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp, subId,
-                "setProvisioningStatusForCapability");
+        checkModifyPhoneStatePermission(subId, "setImsProvisioningStatusForCapability");
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            Phone phone = getPhone(subId);
-            if (phone == null) {
-                loge("setImsProvisioningStatusForCapability: phone instance null for subid "
-                        + subId);
-                return;
-            }
-            if (!doesImsCapabilityRequireProvisioning(phone.getContext(), subId, capability)) {
+            if (!isImsProvisioningRequired(subId, capability, true)) {
                 return;
             }
 
@@ -3490,8 +3913,9 @@
                     break;
                 }
                 default: {
-                    throw new IllegalArgumentException("Tried to set provisioning for capability '"
-                            + capability + "', which does not require provisioning.");
+                    throw new IllegalArgumentException("Tried to set provisioning for "
+                            + "MmTel capability '" + capability + "', which does not require "
+                            + "provisioning. ");
                 }
             }
 
@@ -3510,16 +3934,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            Phone phone = getPhone(subId);
-            if (phone == null) {
-                loge("getImsProvisioningStatusForCapability: phone instance null for subid "
-                        + subId);
-                // We will fail with "true" as the provisioning status because this is the default
-                // if we do not require provisioning.
-                return true;
-            }
-
-            if (!doesImsCapabilityRequireProvisioning(phone.getContext(), subId, capability)) {
+            if (!isImsProvisioningRequired(subId, capability, true)) {
                 return true;
             }
 
@@ -3545,8 +3960,9 @@
                     return isMmTelCapabilityProvisionedInCache(subId, capability, tech);
                 }
                 default: {
-                    throw new IllegalArgumentException("Tried to get provisioning for capability '"
-                            + capability + "', which does not require provisioning.");
+                    throw new IllegalArgumentException(
+                            "Tried to get provisioning for MmTel capability '" + capability
+                                    + "', which does not require provisioning.");
                 }
             }
 
@@ -3655,6 +4071,29 @@
         return false;
     }
 
+    private boolean doesRcsCapabilityRequireProvisioning(Context context, int subId,
+            int capability) {
+        CarrierConfigManager configManager = new CarrierConfigManager(context);
+        PersistableBundle c = configManager.getConfigForSubId(subId);
+
+        boolean requireRcsProvisioning = c.getBoolean(
+                CarrierConfigManager.KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL, false);
+
+        // First check to make sure that the capability requires provisioning.
+        switch (capability) {
+            case RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE:
+                // intentional fallthrough
+            case RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_OPTIONS_UCE: {
+                if (requireRcsProvisioning) {
+                    // OPTION or PRESENCE requires provisioning
+                    return true;
+                }
+                break;
+            }
+        }
+        return false;
+    }
+
     @Override
     public int getImsProvisioningInt(int subId, int key) {
         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
@@ -3778,13 +4217,15 @@
      * Returns the data network type for a subId; does not throw SecurityException.
      */
     @Override
-    public int getNetworkTypeForSubscriber(int subId, String callingPackage) {
+    public int getNetworkTypeForSubscriber(int subId, String callingPackage,
+            String callingFeatureId) {
         final int targetSdk = getTargetSdk(callingPackage);
         if (targetSdk > android.os.Build.VERSION_CODES.Q) {
-            return getDataNetworkTypeForSubscriber(subId, callingPackage);
+            return getDataNetworkTypeForSubscriber(subId, callingPackage, callingFeatureId);
         } else if (targetSdk == android.os.Build.VERSION_CODES.Q
                 && !TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow(
-                        mApp, subId, callingPackage, "getNetworkTypeForSubscriber")) {
+                        mApp, subId, callingPackage, callingFeatureId,
+                "getNetworkTypeForSubscriber")) {
             return TelephonyManager.NETWORK_TYPE_UNKNOWN;
         }
 
@@ -3805,17 +4246,20 @@
      * Returns the data network type
      */
     @Override
-    public int getDataNetworkType(String callingPackage) {
-        return getDataNetworkTypeForSubscriber(getDefaultSubscription(), callingPackage);
+    public int getDataNetworkType(String callingPackage, String callingFeatureId) {
+        return getDataNetworkTypeForSubscriber(getDefaultSubscription(), callingPackage,
+                callingFeatureId);
     }
 
     /**
      * Returns the data network type for a subId
      */
     @Override
-    public int getDataNetworkTypeForSubscriber(int subId, String callingPackage) {
+    public int getDataNetworkTypeForSubscriber(int subId, String callingPackage,
+            String callingFeatureId) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, "getDataNetworkTypeForSubscriber")) {
+                mApp, subId, callingPackage, callingFeatureId,
+                "getDataNetworkTypeForSubscriber")) {
             return TelephonyManager.NETWORK_TYPE_UNKNOWN;
         }
 
@@ -3836,9 +4280,11 @@
      * Returns the Voice network type for a subId
      */
     @Override
-    public int getVoiceNetworkTypeForSubscriber(int subId, String callingPackage) {
+    public int getVoiceNetworkTypeForSubscriber(int subId, String callingPackage,
+            String callingFeatureId) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, "getDataNetworkTypeForSubscriber")) {
+                mApp, subId, callingPackage, callingFeatureId,
+                "getDataNetworkTypeForSubscriber")) {
             return TelephonyManager.NETWORK_TYPE_UNKNOWN;
         }
 
@@ -3892,14 +4338,17 @@
      * or {@link Phone#LTE_ON_CDMA_TRUE}
      */
     @Override
-    public int getLteOnCdmaMode(String callingPackage) {
-        return getLteOnCdmaModeForSubscriber(getDefaultSubscription(), callingPackage);
+    public int getLteOnCdmaMode(String callingPackage, String callingFeatureId) {
+        return getLteOnCdmaModeForSubscriber(getDefaultSubscription(), callingPackage,
+                callingFeatureId);
     }
 
     @Override
-    public int getLteOnCdmaModeForSubscriber(int subId, String callingPackage) {
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, "getLteOnCdmaModeForSubscriber")) {
+    public int getLteOnCdmaModeForSubscriber(int subId, String callingPackage,
+            String callingFeatureId) {
+        try {
+            enforceReadPrivilegedPermission("getLteOnCdmaModeForSubscriber");
+        } catch (SecurityException e) {
             return PhoneConstants.LTE_ON_CDMA_UNKNOWN;
         }
 
@@ -4223,9 +4672,10 @@
      * Get the forbidden PLMN List from the given app type (ex APPTYPE_USIM)
      * on a particular subscription
      */
-    public String[] getForbiddenPlmns(int subId, int appType, String callingPackage) {
+    public String[] getForbiddenPlmns(int subId, int appType, String callingPackage,
+            String callingFeatureId) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, "getForbiddenPlmns")) {
+                mApp, subId, callingPackage, callingFeatureId, "getForbiddenPlmns")) {
             return null;
         }
 
@@ -4257,12 +4707,13 @@
      * @param appType the uicc app type, must be USIM or SIM.
      * @param fplmns the Forbiden plmns list that needed to be written to the SIM.
      * @param callingPackage the op Package name.
+     * @param callingFeatureId the feature in the package.
      * @return number of fplmns that is successfully written to the SIM.
      */
-    public int setForbiddenPlmns(
-            int subId, int appType, List<String> fplmns, String callingPackage) {
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, "setForbiddenPlmns")) {
+    public int setForbiddenPlmns(int subId, int appType, List<String> fplmns, String callingPackage,
+            String callingFeatureId) {
+        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, subId, callingPackage,
+                callingFeatureId, "setForbiddenPlmns")) {
             if (DBG) logv("no permissions for setForbiddenplmns");
             throw new IllegalStateException("No Permissions for setForbiddenPlmns");
         }
@@ -4438,10 +4889,11 @@
         return false;
     }
 
-    public String[] getPcscfAddress(String apnType, String callingPackage) {
+    public String[] getPcscfAddress(String apnType, String callingPackage,
+            String callingFeatureId) {
         final Phone defaultPhone = getDefaultPhone();
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, defaultPhone.getSubId(), callingPackage, "getPcscfAddress")) {
+        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, defaultPhone.getSubId(),
+                callingPackage, callingFeatureId, "getPcscfAddress")) {
             return new String[0];
         }
 
@@ -4454,6 +4906,27 @@
     }
 
     /**
+     * Toggle IMS disable and enable for the framework to reset it. See {@link #enableIms(int)} and
+     * {@link #disableIms(int)}.
+     * @param slotIndex device slot.
+     */
+    public void resetIms(int slotIndex) {
+        enforceModifyPermission();
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            if (mImsResolver == null) {
+                // may happen if the does not support IMS.
+                return;
+            }
+            mImsResolver.disableIms(slotIndex);
+            mImsResolver.enableIms(slotIndex);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
      * Enables IMS for the framework. This will trigger IMS registration and ImsFeature capability
      * status updates, if not already enabled.
      */
@@ -4462,12 +4935,11 @@
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            ImsResolver resolver = PhoneFactory.getImsResolver();
-            if (resolver == null) {
+            if (mImsResolver == null) {
                 // may happen if the device does not support IMS.
                 return;
             }
-            resolver.enableIms(slotId);
+            mImsResolver.enableIms(slotId);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -4482,12 +4954,11 @@
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            ImsResolver resolver = PhoneFactory.getImsResolver();
-            if (resolver == null) {
+            if (mImsResolver == null) {
                 // may happen if the device does not support IMS.
                 return;
             }
-            resolver.disableIms(slotId);
+            mImsResolver.disableIms(slotId);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -4504,12 +4975,11 @@
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            ImsResolver resolver = PhoneFactory.getImsResolver();
-            if (resolver == null) {
+            if (mImsResolver == null) {
                 // may happen if the device does not support IMS.
                 return null;
             }
-            return resolver.getMmTelFeatureAndListen(slotId, callback);
+            return mImsResolver.getMmTelFeatureAndListen(slotId, callback);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -4526,12 +4996,11 @@
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            ImsResolver resolver = PhoneFactory.getImsResolver();
-            if (resolver == null) {
+            if (mImsResolver == null) {
                 // may happen if the device does not support IMS.
                 return null;
             }
-            return resolver.getRcsFeatureAndListen(slotId, callback);
+            return mImsResolver.getRcsFeatureAndListen(slotId, callback);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -4546,12 +5015,11 @@
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            ImsResolver resolver = PhoneFactory.getImsResolver();
-            if (resolver == null) {
+            if (mImsResolver == null) {
                 // may happen if the device does not support IMS.
                 return null;
             }
-            return resolver.getImsRegistration(slotId, feature);
+            return mImsResolver.getImsRegistration(slotId, feature);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -4566,12 +5034,11 @@
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            ImsResolver resolver = PhoneFactory.getImsResolver();
-            if (resolver == null) {
+            if (mImsResolver == null) {
                 // may happen if the device does not support IMS.
                 return null;
             }
-            return resolver.getImsConfig(slotId, feature);
+            return mImsResolver.getImsConfig(slotId, feature);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -4580,58 +5047,65 @@
     /**
      * Sets the ImsService Package Name that Telephony will bind to.
      *
-     * @param slotId the slot ID that the ImsService should bind for.
-     * @param isCarrierImsService true if the ImsService is the carrier override, false if the
+     * @param slotIndex the slot ID that the ImsService should bind for.
+     * @param isCarrierService true if the ImsService is the carrier override, false if the
      *         ImsService is the device default ImsService.
-     * @param packageName The package name of the application that contains the ImsService to bind
-     *         to.
+     * @param featureTypes An integer array of feature types associated with a packageName.
+     * @param packageName The name of the package that the current configuration will be replaced
+     *                    with.
      * @return true if setting the ImsService to bind to succeeded, false if it did not.
-     * @hide
      */
-    public boolean setImsService(int slotId, boolean isCarrierImsService, String packageName) {
-        int[] subIds = SubscriptionManager.getSubId(slotId);
+    public boolean setBoundImsServiceOverride(int slotIndex, boolean isCarrierService,
+            int[] featureTypes, String packageName) {
+        int[] subIds = SubscriptionManager.getSubId(slotIndex);
+        TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(), "setBoundImsServiceOverride");
         TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp,
                 (subIds != null ? subIds[0] : SubscriptionManager.INVALID_SUBSCRIPTION_ID),
-                "setImsService");
+                "setBoundImsServiceOverride");
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            ImsResolver resolver = PhoneFactory.getImsResolver();
-            if (resolver == null) {
+            if (mImsResolver == null) {
                 // may happen if the device does not support IMS.
                 return false;
             }
-            return resolver.overrideImsServiceConfiguration(slotId, isCarrierImsService,
-                    packageName);
+            Map<Integer, String> featureConfig = new HashMap<>();
+            for (int featureType : featureTypes) {
+                featureConfig.put(featureType, packageName);
+            }
+            return mImsResolver.overrideImsServiceConfiguration(slotIndex, isCarrierService,
+                    featureConfig);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
     }
 
     /**
-     * Return the ImsService configuration.
+     * Return the package name of the currently bound ImsService.
      *
      * @param slotId The slot that the ImsService is associated with.
      * @param isCarrierImsService true, if the ImsService is a carrier override, false if it is
      *         the device default.
+     * @param featureType The feature associated with the queried configuration.
      * @return the package name of the ImsService configuration.
      */
-    public String getImsService(int slotId, boolean isCarrierImsService) {
+    public String getBoundImsServicePackage(int slotId, boolean isCarrierImsService,
+            @ImsFeature.FeatureType int featureType) {
         int[] subIds = SubscriptionManager.getSubId(slotId);
-        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp,
-                (subIds != null ? subIds[0] : SubscriptionManager.INVALID_SUBSCRIPTION_ID),
-                "getImsService");
+        TelephonyPermissions
+                .enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
+                mApp, (subIds != null ? subIds[0] : SubscriptionManager.INVALID_SUBSCRIPTION_ID),
+                "getBoundImsServicePackage");
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            ImsResolver resolver = PhoneFactory.getImsResolver();
-            if (resolver == null) {
+            if (mImsResolver == null) {
                 // may happen if the device does not support IMS.
                 return "";
             }
             // TODO: change API to query RCS separately.
-            return resolver.getImsServiceConfiguration(slotId, isCarrierImsService,
-                    ImsFeature.FEATURE_MMTEL);
+            return mImsResolver.getImsServiceConfiguration(slotId, isCarrierImsService,
+                    featureType);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -4691,12 +5165,11 @@
         TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
                 mApp, subId, "setNetworkSelectionModeAutomatic");
 
-        if (!isActiveSubscription(subId)) {
-            return;
-        }
-
         final long identity = Binder.clearCallingIdentity();
         try {
+            if (!isActiveSubscription(subId)) {
+                return;
+            }
             if (DBG) log("setNetworkSelectionModeAutomatic: subId " + subId);
             sendRequest(CMD_SET_NETWORK_SELECTION_MODE_AUTOMATIC, null, subId);
         } finally {
@@ -4743,13 +5216,15 @@
      * Scans for available networks.
      */
     @Override
-    public CellNetworkScanResult getCellNetworkScanResults(int subId, String callingPackage) {
+    public CellNetworkScanResult getCellNetworkScanResults(int subId, String callingPackage,
+            String callingFeatureId) {
         TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
                 mApp, subId, "getCellNetworkScanResults");
         LocationAccessPolicy.LocationPermissionResult locationResult =
                 LocationAccessPolicy.checkLocationPermission(mApp,
                         new LocationAccessPolicy.LocationPermissionQuery.Builder()
                                 .setCallingPackage(callingPackage)
+                                .setCallingFeatureId(callingFeatureId)
                                 .setCallingPid(Binder.getCallingPid())
                                 .setCallingUid(Binder.getCallingUid())
                                 .setMethod("getCellNetworkScanResults")
@@ -4773,6 +5248,75 @@
     }
 
     /**
+     * Get the call forwarding info, given the call forwarding reason.
+     */
+    @Override
+    public CallForwardingInfo getCallForwarding(int subId, int callForwardingReason) {
+        enforceReadPrivilegedPermission("getCallForwarding");
+        long identity = Binder.clearCallingIdentity();
+        try {
+            if (DBG) {
+                log("getCallForwarding: subId " + subId
+                        + " callForwardingReason" + callForwardingReason);
+            }
+            return (CallForwardingInfo) sendRequest(
+                    CMD_GET_CALL_FORWARDING, callForwardingReason, subId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Sets the voice call forwarding info including status (enable/disable), call forwarding
+     * reason, the number to forward, and the timeout before the forwarding is attempted.
+     */
+    @Override
+    public boolean setCallForwarding(int subId, CallForwardingInfo callForwardingInfo) {
+        enforceModifyPermission();
+        long identity = Binder.clearCallingIdentity();
+        try {
+            if (DBG) {
+                log("setCallForwarding: subId " + subId
+                        + " callForwardingInfo" + callForwardingInfo);
+            }
+            return (Boolean) sendRequest(CMD_SET_CALL_FORWARDING, callForwardingInfo, subId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Get the call forwarding info, given the call forwarding reason.
+     */
+    @Override
+    public int getCallWaitingStatus(int subId) {
+        enforceReadPrivilegedPermission("getCallForwarding");
+        long identity = Binder.clearCallingIdentity();
+        try {
+            if (DBG) log("getCallWaitingStatus: subId " + subId);
+            return (Integer) sendRequest(CMD_GET_CALL_WAITING, null, subId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Sets the voice call forwarding info including status (enable/disable), call forwarding
+     * reason, the number to forward, and the timeout before the forwarding is attempted.
+     */
+    @Override
+    public boolean setCallWaitingStatus(int subId, boolean isEnable) {
+        enforceModifyPermission();
+        long identity = Binder.clearCallingIdentity();
+        try {
+            if (DBG) log("setCallWaitingStatus: subId " + subId + " isEnable: " + isEnable);
+            return (Boolean) sendRequest(CMD_SET_CALL_WAITING, isEnable, subId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
      * Starts a new network scan and returns the id of this scan.
      *
      * @param subId id of the subscription
@@ -4783,13 +5327,14 @@
      */
     @Override
     public int requestNetworkScan(int subId, NetworkScanRequest request, Messenger messenger,
-            IBinder binder, String callingPackage) {
+            IBinder binder, String callingPackage, String callingFeatureId) {
         TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
                 mApp, subId, "requestNetworkScan");
         LocationAccessPolicy.LocationPermissionResult locationResult =
                 LocationAccessPolicy.checkLocationPermission(mApp,
                         new LocationAccessPolicy.LocationPermissionQuery.Builder()
                                 .setCallingPackage(callingPackage)
+                                .setCallingFeatureId(callingFeatureId)
                                 .setCallingPid(Binder.getCallingPid())
                                 .setCallingUid(Binder.getCallingUid())
                                 .setMethod("requestNetworkScan")
@@ -4870,10 +5415,10 @@
      * @return the preferred network type, defined in RILConstants.java.
      */
     @Override
-    public int getCalculatedPreferredNetworkType(String callingPackage) {
+    public int getCalculatedPreferredNetworkType(String callingPackage, String callingFeatureId) {
         final Phone defaultPhone = getDefaultPhone();
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, defaultPhone.getSubId(),
-                callingPackage, "getCalculatedPreferredNetworkType")) {
+                callingPackage, callingFeatureId, "getCalculatedPreferredNetworkType")) {
             return RILConstants.PREFERRED_NETWORK_MODE;
         }
 
@@ -4924,21 +5469,81 @@
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            if (DBG) log("setPreferredNetworkType: subId " + subId + " type " + networkType);
-            Boolean success = (Boolean) sendRequest(
-                    CMD_SET_PREFERRED_NETWORK_TYPE, networkType, subId);
-            if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
-            if (success) {
-                Settings.Global.putInt(mApp.getContentResolver(),
-                        Settings.Global.PREFERRED_NETWORK_MODE + subId, networkType);
-            }
-            return success;
+            Settings.Global.putInt(mApp.getContentResolver(),
+                    Settings.Global.PREFERRED_NETWORK_MODE + subId, networkType);
+            return setPreferredNetworkTypesInternal(subId);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
     }
 
     /**
+     * Get the allowed network types that store in the telephony provider.
+     *
+     * @param subId the id of the subscription.
+     * @return allowedNetworkTypes the allowed network types.
+     */
+    @Override
+    public long getAllowedNetworkTypes(int subId) {
+        TelephonyPermissions
+                .enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
+                    mApp, subId, "getAllowedNetworkTypes");
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return SubscriptionManager.getLongSubscriptionProperty(
+                    subId, SubscriptionManager.ALLOWED_NETWORK_TYPES, -1, mApp);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Set the allowed network types.
+     *
+     * @param subId the id of the subscription.
+     * @param allowedNetworkTypes the allowed network types.
+     * @return true on success; false on any failure.
+     */
+    @Override
+    public boolean setAllowedNetworkTypes(int subId, long allowedNetworkTypes) {
+        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+                mApp, subId, "setAllowedNetworkTypes");
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            SubscriptionManager.setSubscriptionProperty(subId,
+                    SubscriptionManager.ALLOWED_NETWORK_TYPES,
+                    String.valueOf(allowedNetworkTypes));
+            return setPreferredNetworkTypesInternal(subId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private boolean setPreferredNetworkTypesInternal(int subId) {
+        long networkTypeBitMask = RadioAccessFamily.getRafFromNetworkType(
+                Settings.Global.getInt(mApp.getContentResolver(),
+                        Settings.Global.PREFERRED_NETWORK_MODE + subId,
+                        RILConstants.PREFERRED_NETWORK_MODE));
+        long allowedNetworkTypes = SubscriptionManager.getLongSubscriptionProperty(
+                subId, SubscriptionManager.ALLOWED_NETWORK_TYPES, -1, mApp);
+        int networkMode = RadioAccessFamily.getNetworkTypeFromRaf(
+                (int) (networkTypeBitMask & allowedNetworkTypes));
+
+        if (DBG) {
+            log("setPreferredNetworkTypesInternal: subId " + subId
+                    + " networkTypes " + networkTypeBitMask
+                    + " allowedNetworkTypes " + allowedNetworkTypes
+                    + " networkMode " + networkMode);
+        }
+
+        Boolean success = (Boolean) sendRequest(
+                CMD_SET_PREFERRED_NETWORK_TYPE, networkMode, subId);
+        if (DBG) log("setPreferredNetworkTypesInternal: " + (success ? "ok" : "fail"));
+        return success;
+    }
+
+    /**
      * Check whether DUN APN is required for tethering with subId.
      *
      * @param subId the id of the subscription to require tethering.
@@ -4989,6 +5594,34 @@
     }
 
     /**
+     * Enable or disable always reporting signal strength changes from radio.
+     *
+     * @param isEnable {@code true} for enabling; {@code false} for disabling.
+     */
+    @Override
+    public void setAlwaysReportSignalStrength(int subId, boolean isEnable) {
+        enforceModifyPermission();
+        enforceSystemCaller();
+
+        final long identity = Binder.clearCallingIdentity();
+        final Phone phone = getPhone(subId);
+        try {
+            if (phone != null) {
+                if (DBG) {
+                    log("setAlwaysReportSignalStrength: subId=" + subId
+                            + " isEnable=" + isEnable);
+                }
+                phone.setAlwaysReportSignalStrength(isEnable);
+            } else {
+                loge("setAlwaysReportSignalStrength: no phone found for subId="
+                        + subId);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
      * Get the user enabled state of Mobile Data.
      *
      * TODO: remove and use isUserDataEnabled.
@@ -5042,24 +5675,15 @@
     }
 
     /**
-     * Get whether mobile data is enabled.
+     * Checks if the device is capable of mobile data by considering whether whether the
+     * user has enabled mobile data, whether the carrier has enabled mobile data, and
+     * whether the network policy allows data connections.
      *
-     * Comparable to {@link #isUserDataEnabled(int)}, this considers all factors deciding
-     * whether mobile data is actually enabled.
-     *
-     * Accepts either ACCESS_NETWORK_STATE, MODIFY_PHONE_STATE or carrier privileges.
-     *
-     * @return {@code true} if data is enabled else {@code false}
+     * @return {@code true} if the overall data connection is capable; {@code false} if not.
      */
     @Override
     public boolean isDataEnabled(int subId) {
-        try {
-            mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
-                    null);
-        } catch (Exception e) {
-            TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
-                    mApp, subId, "isDataEnabled");
-        }
+        enforceReadPrivilegedPermission("isDataEnabled");
 
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -5079,14 +5703,13 @@
         }
     }
 
-    private int getCarrierPrivilegeStatusFromCarrierConfigRules(int privilegeFromSim,
+    private int getCarrierPrivilegeStatusFromCarrierConfigRules(int privilegeFromSim, int uid,
             Phone phone) {
         //load access rules from carrier configs, and check those as well: b/139133814
         SubscriptionController subController = SubscriptionController.getInstance();
         if (privilegeFromSim == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
                 || subController == null) return privilegeFromSim;
 
-        int uid = Binder.getCallingUid();
         PackageManager pkgMgr = phone.getContext().getPackageManager();
         String[] packages = pkgMgr.getPackagesForUid(uid);
 
@@ -5140,11 +5763,12 @@
 
         return getCarrierPrivilegeStatusFromCarrierConfigRules(
             card.getCarrierPrivilegeStatusForCurrentTransaction(
-                phone.getContext().getPackageManager()), phone);
+                phone.getContext().getPackageManager()), Binder.getCallingUid(), phone);
     }
 
     @Override
     public int getCarrierPrivilegeStatusForUid(int subId, int uid) {
+        enforceReadPrivilegedPermission("getCarrierPrivilegeStatusForUid");
         final Phone phone = getPhone(subId);
         if (phone == null) {
             loge("getCarrierPrivilegeStatusForUid: Invalid subId");
@@ -5157,8 +5781,8 @@
             return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
         }
         return getCarrierPrivilegeStatusFromCarrierConfigRules(
-            profile.getCarrierPrivilegeStatusForUid(
-                phone.getContext().getPackageManager(), uid), phone);
+                profile.getCarrierPrivilegeStatusForUid(
+                        phone.getContext().getPackageManager(), uid), uid, phone);
     }
 
     @Override
@@ -5230,7 +5854,7 @@
                         PackageManager.MATCH_DISABLED_COMPONENTS
                             | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
                             | PackageManager.GET_SIGNING_CERTIFICATES,
-                            UserHandle.USER_SYSTEM);
+                            UserHandle.SYSTEM.getIdentifier());
                 }
                 for (int p = packages.size() - 1; p >= 0; p--) {
                     PackageInfo pkgInfo = packages.get(p);
@@ -5280,7 +5904,7 @@
     @Override
     public boolean setLine1NumberForDisplayForSubscriber(int subId, String alphaTag,
             String number) {
-        TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(
+        TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mApp,
                 subId, "setLine1NumberForDisplayForSubscriber");
 
         final long identity = Binder.clearCallingIdentity();
@@ -5293,7 +5917,7 @@
             final String subscriberId = phone.getSubscriberId();
 
             if (DBG_MERGE) {
-                Slog.d(LOG_TAG, "Setting line number for ICC=" + iccId + ", subscriberId="
+                Rlog.d(LOG_TAG, "Setting line number for ICC=" + iccId + ", subscriberId="
                         + subscriberId + " to " + number);
             }
 
@@ -5330,10 +5954,11 @@
     }
 
     @Override
-    public String getLine1NumberForDisplay(int subId, String callingPackage) {
+    public String getLine1NumberForDisplay(int subId, String callingPackage,
+            String callingFeatureId) {
         // This is open to apps with WRITE_SMS.
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneNumber(
-                mApp, subId, callingPackage, "getLine1NumberForDisplay")) {
+                mApp, subId, callingPackage, callingFeatureId, "getLine1NumberForDisplay")) {
             if (DBG_MERGE) log("getLine1NumberForDisplay returning null due to permission");
             return null;
         }
@@ -5357,9 +5982,10 @@
     }
 
     @Override
-    public String getLine1AlphaTagForDisplay(int subId, String callingPackage) {
+    public String getLine1AlphaTagForDisplay(int subId, String callingPackage,
+            String callingFeatureId) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, "getLine1AlphaTagForDisplay")) {
+                mApp, subId, callingPackage, callingFeatureId, "getLine1AlphaTagForDisplay")) {
             return null;
         }
 
@@ -5377,12 +6003,13 @@
     }
 
     @Override
-    public String[] getMergedSubscriberIds(int subId, String callingPackage) {
+    public String[] getMergedSubscriberIds(int subId, String callingPackage,
+            String callingFeatureId) {
         // This API isn't public, so no need to provide a valid subscription ID - we're not worried
         // about carrier-privileged callers not having access.
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
                 mApp, SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage,
-                "getMergedSubscriberIds")) {
+                callingFeatureId, "getMergedSubscriberIds")) {
             return null;
         }
 
@@ -5416,7 +6043,7 @@
                         final String numberKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
                         mergeNumber = (String) prefs.get(numberKey);
                         if (DBG_MERGE) {
-                            Slog.d(LOG_TAG, "Found line number " + mergeNumber
+                            Rlog.d(LOG_TAG, "Found line number " + mergeNumber
                                     + " for active subscriber " + subscriberId);
                         }
                         if (!TextUtils.isEmpty(mergeNumber)) {
@@ -5450,7 +6077,7 @@
             final String[] resultArray = result.toArray(new String[result.size()]);
             Arrays.sort(resultArray);
             if (DBG_MERGE) {
-                Slog.d(LOG_TAG,
+                Rlog.d(LOG_TAG,
                         "Found subscribers " + Arrays.toString(resultArray) + " after merge");
             }
             return resultArray;
@@ -5487,7 +6114,8 @@
             // Get all subscriberIds from the group.
             final List<String> mergedSubscriberIds = new ArrayList<>();
             final List<SubscriptionInfo> groupInfos = SubscriptionController.getInstance()
-                    .getSubscriptionsInGroup(groupUuid, mApp.getOpPackageName());
+                    .getSubscriptionsInGroup(groupUuid, mApp.getOpPackageName(),
+                            null);
             for (SubscriptionInfo subInfo : groupInfos) {
                 subscriberId = telephonyManager.getSubscriberId(subInfo.getSubscriptionId());
                 if (subscriberId != null) {
@@ -5504,7 +6132,7 @@
 
     @Override
     public boolean setOperatorBrandOverride(int subId, String brand) {
-        TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(
+        TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mApp,
                 subId, "setOperatorBrandOverride");
 
         final long identity = Binder.clearCallingIdentity();
@@ -5520,7 +6148,8 @@
     public boolean setRoamingOverride(int subId, List<String> gsmRoamingList,
             List<String> gsmNonRoamingList, List<String> cdmaRoamingList,
             List<String> cdmaNonRoamingList) {
-        TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(subId, "setRoamingOverride");
+        TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(
+                mApp, subId, "setRoamingOverride");
 
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -5611,10 +6240,10 @@
     }
 
     @Override
-    public boolean isVideoCallingEnabled(String callingPackage) {
+    public boolean isVideoCallingEnabled(String callingPackage, String callingFeatureId) {
         final Phone defaultPhone = getDefaultPhone();
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, defaultPhone.getSubId(), callingPackage, "isVideoCallingEnabled")) {
+        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, defaultPhone.getSubId(),
+                callingPackage, callingFeatureId, "isVideoCallingEnabled")) {
             return false;
         }
 
@@ -5635,9 +6264,11 @@
     }
 
     @Override
-    public boolean canChangeDtmfToneLength(int subId, String callingPackage) {
+    public boolean canChangeDtmfToneLength(int subId, String callingPackage,
+            String callingFeatureId) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, "isVideoCallingEnabled")) {
+                mApp, subId, callingPackage, callingFeatureId,
+                "isVideoCallingEnabled")) {
             return false;
         }
 
@@ -5653,9 +6284,9 @@
     }
 
     @Override
-    public boolean isWorldPhone(int subId, String callingPackage) {
+    public boolean isWorldPhone(int subId, String callingPackage, String callingFeatureId) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, "isVideoCallingEnabled")) {
+                mApp, subId, callingPackage, callingFeatureId, "isVideoCallingEnabled")) {
             return false;
         }
 
@@ -5719,12 +6350,23 @@
     public boolean isRttEnabled(int subscriptionId) {
         final long identity = Binder.clearCallingIdentity();
         try {
-            return isRttSupported(subscriptionId);
+            boolean isRttSupported = isRttSupported(subscriptionId);
+            boolean isUserRttSettingOn = Settings.Secure.getInt(
+                    mApp.getContentResolver(), Settings.Secure.RTT_CALLING_MODE, 0) != 0;
+            boolean shouldIgnoreUserRttSetting = mApp.getCarrierConfigForSubId(subscriptionId)
+                    .getBoolean(CarrierConfigManager.KEY_IGNORE_RTT_MODE_SETTING_BOOL);
+            return isRttSupported && (isUserRttSettingOn || shouldIgnoreUserRttSetting);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
     }
 
+    @Deprecated
+    @Override
+    public String getDeviceId(String callingPackage) {
+        return getDeviceIdWithFeature(callingPackage, null);
+    }
+
     /**
      * Returns the unique device ID of phone, for example, the IMEI for
      * GSM and the MEID for CDMA phones. Return null if device ID is not available.
@@ -5733,14 +6375,14 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
     @Override
-    public String getDeviceId(String callingPackage) {
+    public String getDeviceIdWithFeature(String callingPackage, String callingFeatureId) {
         final Phone phone = PhoneFactory.getPhone(0);
         if (phone == null) {
             return null;
         }
         int subId = phone.getSubId();
         if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mApp, subId,
-                callingPackage, "getDeviceId")) {
+                callingPackage, callingFeatureId, "getDeviceId")) {
             return null;
         }
 
@@ -5779,9 +6421,9 @@
 
     @Override
     public int getSubIdForPhoneAccountHandle(
-            PhoneAccountHandle phoneAccountHandle, String callingPackage) {
+            PhoneAccountHandle phoneAccountHandle, String callingPackage, String callingFeatureId) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, getDefaultSubscription(),
-                callingPackage, "getSubIdForPhoneAccountHandle")) {
+                callingPackage, callingFeatureId, "getSubIdForPhoneAccountHandle")) {
             throw new SecurityException("Requires READ_PHONE_STATE permission.");
         }
         final long identity = Binder.clearCallingIdentity();
@@ -5915,7 +6557,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             final SubscriptionInfo info = mSubscriptionController.getActiveSubscriptionInfo(subId,
-                    phone.getContext().getOpPackageName());
+                    phone.getContext().getOpPackageName(), null);
             if (info == null) {
                 log("getSimLocaleForSubscriber, inactive subId: " + subId);
                 return null;
@@ -5939,7 +6581,7 @@
             // exact locale (e.g. fr_FR = French/France). So, if the locale returned from
             // the SIM and carrier preferences does not include a country we add the country
             // determined from the SIM MCC to provide an exact locale.
-            final Locale mccLocale = MccTable.getLocaleFromMcc(mApp, mcc, simLanguage);
+            final Locale mccLocale = LocaleUtils.getLocaleFromMcc(mApp, mcc, simLanguage);
             if (mccLocale != null) {
                 if (DBG) log("No locale from SIM, using mcc locale:" + mccLocale);
                 return mccLocale.toLanguageTag();
@@ -5953,18 +6595,20 @@
     }
 
     private List<SubscriptionInfo> getAllSubscriptionInfoList() {
-        return mSubscriptionController.getAllSubInfoList(mApp.getOpPackageName());
+        return mSubscriptionController.getAllSubInfoList(mApp.getOpPackageName(),
+                null);
     }
 
     /**
      * NOTE: this method assumes permission checks are done and caller identity has been cleared.
      */
     private List<SubscriptionInfo> getActiveSubscriptionInfoListPrivileged() {
-        return mSubscriptionController.getActiveSubscriptionInfoList(mApp.getOpPackageName());
+        return mSubscriptionController.getActiveSubscriptionInfoList(mApp.getOpPackageName(),
+                null);
     }
 
     private final ModemActivityInfo mLastModemActivityInfo =
-            new ModemActivityInfo(0, 0, 0, new int[0], 0, 0);
+            new ModemActivityInfo(0, 0, 0, new int[0], 0);
 
     /**
      * Responds to the ResultReceiver with the {@link android.telephony.ModemActivityInfo} object
@@ -5981,38 +6625,7 @@
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            ModemActivityInfo ret = null;
-            synchronized (mLastModemActivityInfo) {
-                ModemActivityInfo info = (ModemActivityInfo) sendRequest(
-                        CMD_GET_MODEM_ACTIVITY_INFO,
-                        null, workSource);
-                if (isModemActivityInfoValid(info)) {
-                    int[] mergedTxTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
-                    for (int i = 0; i < mergedTxTimeMs.length; i++) {
-                        mergedTxTimeMs[i] = info.getTxTimeMillis()[i]
-                                + mLastModemActivityInfo.getTxTimeMillis()[i];
-                    }
-                    mLastModemActivityInfo.setTimestamp(info.getTimestamp());
-                    mLastModemActivityInfo.setSleepTimeMillis(info.getSleepTimeMillis()
-                            + mLastModemActivityInfo.getSleepTimeMillis());
-                    mLastModemActivityInfo.setIdleTimeMillis(
-                            info.getIdleTimeMillis() + mLastModemActivityInfo.getIdleTimeMillis());
-                    mLastModemActivityInfo.setTxTimeMillis(mergedTxTimeMs);
-                    mLastModemActivityInfo.setRxTimeMillis(
-                            info.getRxTimeMillis() + mLastModemActivityInfo.getRxTimeMillis());
-                    mLastModemActivityInfo.setEnergyUsed(
-                            info.getEnergyUsed() + mLastModemActivityInfo.getEnergyUsed());
-                }
-                ret = new ModemActivityInfo(mLastModemActivityInfo.getTimestamp(),
-                        mLastModemActivityInfo.getSleepTimeMillis(),
-                        mLastModemActivityInfo.getIdleTimeMillis(),
-                        mLastModemActivityInfo.getTxTimeMillis(),
-                        mLastModemActivityInfo.getRxTimeMillis(),
-                        mLastModemActivityInfo.getEnergyUsed());
-            }
-            Bundle bundle = new Bundle();
-            bundle.putParcelable(TelephonyManager.MODEM_ACTIVITY_RESULT_KEY, ret);
-            result.send(0, bundle);
+            sendRequestAsync(CMD_GET_MODEM_ACTIVITY_INFO, result, null, workSource);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -6027,13 +6640,14 @@
         int activityDurationMs =
             (int) (info.getTimestamp() - mLastModemActivityInfo.getTimestamp());
         int totalTxTimeMs = 0;
-        for (int i = 0; i < info.getTxTimeMillis().length; i++) {
-            totalTxTimeMs += info.getTxTimeMillis()[i];
+        int[] txTimeMs = info.getTransmitTimeMillis();
+        for (int i = 0; i < info.getTransmitPowerInfo().size(); i++) {
+            totalTxTimeMs += txTimeMs[i];
         }
         return (info.isValid()
             && (info.getSleepTimeMillis() <= activityDurationMs)
             && (info.getIdleTimeMillis() <= activityDurationMs)
-            && (info.getRxTimeMillis() <= activityDurationMs)
+            && (info.getReceiveTimeMillis() <= activityDurationMs)
             && (totalTxTimeMs <= activityDurationMs));
     }
 
@@ -6042,9 +6656,10 @@
      * Returns the service state information on specified subscription.
      */
     @Override
-    public ServiceState getServiceStateForSubscriber(int subId, String callingPackage) {
+    public ServiceState getServiceStateForSubscriber(int subId, String callingPackage,
+            String callingFeatureId) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, "getServiceStateForSubscriber")) {
+                mApp, subId, callingPackage, callingFeatureId, "getServiceStateForSubscriber")) {
             return null;
         }
 
@@ -6052,6 +6667,7 @@
                 LocationAccessPolicy.checkLocationPermission(mApp,
                         new LocationAccessPolicy.LocationPermissionQuery.Builder()
                                 .setCallingPackage(callingPackage)
+                                .setCallingFeatureId(callingFeatureId)
                                 .setCallingPid(Binder.getCallingPid())
                                 .setCallingUid(Binder.getCallingUid())
                                 .setMethod("getServiceStateForSubscriber")
@@ -6063,6 +6679,7 @@
                 LocationAccessPolicy.checkLocationPermission(mApp,
                         new LocationAccessPolicy.LocationPermissionQuery.Builder()
                                 .setCallingPackage(callingPackage)
+                                .setCallingFeatureId(callingFeatureId)
                                 .setCallingPid(Binder.getCallingPid())
                                 .setCallingUid(Binder.getCallingUid())
                                 .setMethod("getServiceStateForSubscriber")
@@ -6087,8 +6704,8 @@
             // Scrub out the location info in ServiceState depending on what level of access
             // the caller has.
             if (hasFinePermission) return ss;
-            if (hasCoarsePermission) return ss.sanitizeLocationInfo(false);
-            return ss.sanitizeLocationInfo(true);
+            if (hasCoarsePermission) return ss.createLocationInfoSanitizedCopy(false);
+            return ss.createLocationInfoSanitizedCopy(true);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -6539,33 +7156,6 @@
     }
 
     /**
-     * Get aggregated video call data usage since boot.
-     *
-     * @param perUidStats True if requesting data usage per uid, otherwise overall usage.
-     * @return Snapshot of video call data usage
-     * {@hide}
-     */
-    @Override
-    public NetworkStats getVtDataUsage(int subId, boolean perUidStats) {
-        mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_NETWORK_USAGE_HISTORY,
-                null);
-
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            // NetworkStatsService keeps tracking the active network interface and identity. It
-            // records the delta with the corresponding network identity.
-            // We just return the total video call data usage snapshot since boot.
-            Phone phone = getPhone(subId);
-            if (phone != null) {
-                return phone.getVtDataUsage(perUidStats);
-            }
-            return null;
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    /**
      * Policy control of data connection. Usually used when data limit is passed.
      * @param enabled True if enabling the data, otherwise disabling.
      * @param subId Subscription index
@@ -6592,9 +7182,10 @@
      * @hide
      */
     @Override
-    public List<ClientRequestStats> getClientRequestStats(String callingPackage, int subId) {
+    public List<ClientRequestStats> getClientRequestStats(String callingPackage,
+            String callingFeatureId, int subId) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, "getClientRequestStats")) {
+                mApp, subId, callingPackage, callingFeatureId, "getClientRequestStats")) {
             return null;
         }
         Phone phone = getPhone(subId);
@@ -6705,14 +7296,15 @@
      * Get the current modem radio state for the given slot.
      * @param slotIndex slot index.
      * @param callingPackage the name of the package making the call.
+     * @param callingFeatureId The feature in the package.
      * @return the current radio power state from the modem
      */
     @Override
-    public int getRadioPowerState(int slotIndex, String callingPackage) {
+    public int getRadioPowerState(int slotIndex, String callingPackage, String callingFeatureId) {
         Phone phone = PhoneFactory.getPhone(slotIndex);
         if (phone != null) {
-            if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                    mApp, phone.getSubId(), callingPackage, "getRadioPowerState")) {
+            if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, phone.getSubId(),
+                    callingPackage, callingFeatureId, "getRadioPowerState")) {
                 return TelephonyManager.RADIO_POWER_UNAVAILABLE;
             }
 
@@ -6786,7 +7378,8 @@
 
     @Override
     public boolean isManualNetworkSelectionAllowed(int subId) {
-        TelephonyPermissions.enforeceCallingOrSelfReadPhoneStatePermissionOrCarrierPrivilege(
+        TelephonyPermissions
+                .enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
                 mApp, subId, "isManualNetworkSelectionAllowed");
 
         boolean isAllowed = true;
@@ -6942,23 +7535,6 @@
         }
     }
 
-    @Override
-    public void setRadioIndicationUpdateMode(int subId, int filters, int mode) {
-        enforceModifyPermission();
-        final Phone phone = getPhone(subId);
-        if (phone == null) {
-            loge("setRadioIndicationUpdateMode fails with invalid subId: " + subId);
-            return;
-        }
-
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            phone.setRadioIndicationUpdateMode(filters, mode);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
     /**
      * A test API to reload the UICC profile.
      *
@@ -6994,8 +7570,7 @@
      * Returns false if the mobile data is disabled by default, otherwise return true.
      */
     private boolean getDefaultDataEnabled() {
-        return "true".equalsIgnoreCase(
-                SystemProperties.get(DEFAULT_MOBILE_DATA_PROPERTY_NAME, "true"));
+        return TelephonyProperties.mobile_data().orElse(true);
     }
 
     /**
@@ -7006,8 +7581,7 @@
     private boolean getDefaultDataRoamingEnabled(int subId) {
         final CarrierConfigManager configMgr = (CarrierConfigManager)
                 mApp.getSystemService(Context.CARRIER_CONFIG_SERVICE);
-        boolean isDataRoamingEnabled = "true".equalsIgnoreCase(
-                SystemProperties.get(DEFAULT_DATA_ROAMING_PROPERTY_NAME, "false"));
+        boolean isDataRoamingEnabled = TelephonyProperties.data_roaming().orElse(true);
         isDataRoamingEnabled |= configMgr.getConfigForSubId(subId).getBoolean(
                 CarrierConfigManager.KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL);
         return isDataRoamingEnabled;
@@ -7018,11 +7592,12 @@
      * not set, return {@link Phone#PREFERRED_NT_MODE}.
      */
     private int getDefaultNetworkType(int subId) {
-        return Integer.parseInt(
-                TelephonyManager.getTelephonyProperty(
-                        mSubscriptionController.getPhoneId(subId),
-                        DEFAULT_NETWORK_MODE_PROPERTY_NAME,
-                        String.valueOf(Phone.PREFERRED_NT_MODE)));
+        List<Integer> list = TelephonyProperties.default_network();
+        int phoneId = mSubscriptionController.getPhoneId(subId);
+        if (phoneId >= 0 && phoneId < list.size() && list.get(phoneId) != null) {
+            return list.get(phoneId);
+        }
+        return Phone.PREFERRED_NT_MODE;
     }
 
     @Override
@@ -7062,9 +7637,11 @@
     }
 
     @Override
-    public int getNumberOfModemsWithSimultaneousDataConnections(int subId, String callingPackage) {
+    public int getNumberOfModemsWithSimultaneousDataConnections(int subId, String callingPackage,
+            String callingFeatureId) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, "getNumberOfModemsWithSimultaneousDataConnections")) {
+                mApp, subId, callingPackage, callingFeatureId,
+                "getNumberOfModemsWithSimultaneousDataConnections")) {
             return -1;
         }
 
@@ -7078,7 +7655,8 @@
 
     @Override
     public int getCdmaRoamingMode(int subId) {
-        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+        TelephonyPermissions
+                .enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
                 mApp, subId, "getCdmaRoamingMode");
 
         final long identity = Binder.clearCallingIdentity();
@@ -7117,9 +7695,10 @@
 
     @Override
     public Map<Integer, List<EmergencyNumber>> getEmergencyNumberList(
-            String callingPackage) {
+            String callingPackage, String callingFeatureId) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, getDefaultSubscription(), callingPackage, "getEmergencyNumberList")) {
+                mApp, getDefaultSubscription(), callingPackage, callingFeatureId,
+                "getEmergencyNumberList")) {
             throw new SecurityException("Requires READ_PHONE_STATE permission.");
         }
         final long identity = Binder.clearCallingIdentity();
@@ -7245,7 +7824,7 @@
     }
 
     @Override
-    public void updateTestOtaEmergencyNumberDbFilePath(String otaFilePath) {
+    public void updateOtaEmergencyNumberDbFilePath(ParcelFileDescriptor otaParcelFileDescriptor) {
         enforceActiveEmergencySessionPermission();
 
         final long identity = Binder.clearCallingIdentity();
@@ -7253,7 +7832,24 @@
             for (Phone phone: PhoneFactory.getPhones()) {
                 EmergencyNumberTracker tracker = phone.getEmergencyNumberTracker();
                 if (tracker != null) {
-                    tracker.updateTestOtaEmergencyNumberDbFilePath(otaFilePath);
+                    tracker.updateOtaEmergencyNumberDbFilePath(otaParcelFileDescriptor);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void resetOtaEmergencyNumberDbFilePath() {
+        enforceActiveEmergencySessionPermission();
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            for (Phone phone: PhoneFactory.getPhones()) {
+                EmergencyNumberTracker tracker = phone.getEmergencyNumberTracker();
+                if (tracker != null) {
+                    tracker.resetOtaEmergencyNumberDbFilePath();
                 }
             }
         } finally {
@@ -7305,12 +7901,14 @@
      * Whether a modem stack is enabled or not.
      */
     @Override
-    public boolean isModemEnabledForSlot(int slotIndex, String callingPackage) {
+    public boolean isModemEnabledForSlot(int slotIndex, String callingPackage,
+            String callingFeatureId) {
         Phone phone = PhoneFactory.getPhone(slotIndex);
         if (phone == null) return false;
 
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, phone.getSubId(), callingPackage, "isModemEnabledForSlot")) {
+                mApp, phone.getSubId(), callingPackage, callingFeatureId,
+                "isModemEnabledForSlot")) {
             throw new SecurityException("Requires READ_PHONE_STATE permission.");
         }
 
@@ -7342,9 +7940,10 @@
 
     @Override
     @TelephonyManager.IsMultiSimSupportedResult
-    public int isMultiSimSupported(String callingPackage) {
+    public int isMultiSimSupported(String callingPackage, String callingFeatureId) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp,
-                getDefaultPhone().getSubId(), callingPackage, "isMultiSimSupported")) {
+                getDefaultPhone().getSubId(), callingPackage, callingFeatureId,
+                "isMultiSimSupported")) {
             return TelephonyManager.MULTISIM_NOT_SUPPORTED_BY_HARDWARE;
         }
 
@@ -7445,9 +8044,11 @@
      * Return value defaults to true.
      */
     @Override
-    public boolean doesSwitchMultiSimConfigTriggerReboot(int subId, String callingPackage) {
+    public boolean doesSwitchMultiSimConfigTriggerReboot(int subId, String callingPackage,
+            String callingFeatureId) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, "doesSwitchMultiSimConfigTriggerReboot")) {
+                mApp, subId, callingPackage, callingFeatureId,
+                "doesSwitchMultiSimConfigTriggerReboot")) {
             return false;
         }
         final long identity = Binder.clearCallingIdentity();
@@ -7498,6 +8099,15 @@
     }
 
     /**
+     * Get the current calling package name.
+     * @return the current calling package name
+     */
+    @Override
+    public String getCurrentPackageName() {
+        return mApp.getPackageManager().getPackagesForUid(Binder.getCallingUid())[0];
+    }
+
+    /**
      * Return whether data is enabled for certain APN type. This will tell if framework will accept
      * corresponding network requests on a subId.
      *
@@ -7505,7 +8115,7 @@
      *  1) user data is turned on, or
      *  2) APN is un-metered for this subscription, or
      *  3) APN type is whitelisted. E.g. MMS is whitelisted if
-     *  {@link SubscriptionManager#setAlwaysAllowMmsData} is turned on.
+     *  {@link TelephonyManager#setAlwaysAllowMmsData} is turned on.
      *
      * @return whether data is allowed for a apn type.
      *
@@ -7546,10 +8156,59 @@
     }
 
     @Override
-    public void enqueueSmsPickResult(String callingPackage, IIntegerConsumer pendingSubIdResult) {
+    public void setSystemSelectionChannels(List<RadioAccessSpecifier> specifiers,
+            int subscriptionId, IBooleanConsumer resultCallback) {
+        enforceModifyPermission();
+        long token = Binder.clearCallingIdentity();
+        try {
+            Phone phone = getPhone(subscriptionId);
+            if (phone == null) {
+                try {
+                    if (resultCallback != null) {
+                        resultCallback.accept(false);
+                    }
+                } catch (RemoteException e) {
+                    // ignore
+                }
+                return;
+            }
+            Pair<List<RadioAccessSpecifier>, Consumer<Boolean>> argument =
+                    Pair.create(specifiers, (x) -> {
+                        try {
+                            if (resultCallback != null) {
+                                resultCallback.accept(x);
+                            }
+                        } catch (RemoteException e) {
+                            // ignore
+                        }
+                    });
+            sendRequestAsync(CMD_SET_SYSTEM_SELECTION_CHANNELS, argument, phone, null);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    @Override
+    public boolean isMvnoMatched(int subId, int mvnoType, @NonNull String mvnoMatchData) {
+        IccRecords iccRecords = UiccController.getInstance().getIccRecords(
+                SubscriptionManager.getPhoneId(subId), UiccController.APP_FAM_3GPP);
+        if (iccRecords == null) {
+            Log.d(LOG_TAG, "isMvnoMatched# IccRecords is null");
+            return false;
+        }
+        return ApnSettingUtils.mvnoMatches(iccRecords, mvnoType, mvnoMatchData);
+    }
+
+    @Override
+    public void enqueueSmsPickResult(String callingPackage, String callingAttributionTag,
+            IIntegerConsumer pendingSubIdResult) {
+        if (callingPackage == null) {
+            callingPackage = getCurrentPackageName();
+        }
         SmsPermissions permissions = new SmsPermissions(getDefaultPhone(), mApp,
                 (AppOpsManager) mApp.getSystemService(Context.APP_OPS_SERVICE));
-        if (!permissions.checkCallingCanSendSms(callingPackage, "Sending message")) {
+        if (!permissions.checkCallingCanSendSms(callingPackage, callingAttributionTag,
+                "Sending message")) {
             throw new SecurityException("Requires SEND_SMS permission to perform this operation");
         }
         PickSmsSubscriptionActivity.addPendingResult(pendingSubIdResult);
@@ -7618,6 +8277,22 @@
         }
     }
 
+    @Override
+    public boolean setAlwaysAllowMmsData(int subId, boolean alwaysAllow) {
+        enforceModifyPermission();
+
+        // Now that all security checks passes, perform the operation as ourselves.
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            Phone phone = getPhone(subId);
+            if (phone == null) return false;
+
+            return phone.getDataEnabledSettings().setAlwaysAllowMmsData(alwaysAllow);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     /**
      * Updates whether conference event pacakge handling is enabled.
      * @param isCepEnabled {@code true} if CEP handling is enabled (default), or {@code false}
@@ -7645,4 +8320,106 @@
             Binder.restoreCallingIdentity(identity);
         }
     }
+
+    /**
+     * Notify that an RCS autoconfiguration XML file has been received for provisioning.
+     *
+     * @param config       The XML file to be read. ASCII/UTF8 encoded text if not compressed.
+     * @param isCompressed The XML file is compressed in gzip format and must be decompressed
+     *                     before being read.
+     */
+    @Override
+    public void notifyRcsAutoConfigurationReceived(int subId, @NonNull byte[] config, boolean
+            isCompressed) {
+        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+                mApp, subId, "notifyRcsAutoConfigurationReceived");
+        try {
+            IImsConfig configBinder = getImsConfig(getSlotIndex(subId), ImsFeature.FEATURE_RCS);
+            if (configBinder == null) {
+                Rlog.e(LOG_TAG, "null result for getImsConfig");
+            } else {
+                configBinder.notifyRcsAutoConfigurationReceived(config, isCompressed);
+            }
+        } catch (RemoteException e) {
+            Rlog.e(LOG_TAG, "fail to getImsConfig " + e.getMessage());
+        }
+    }
+
+    @Override
+    public boolean isIccLockEnabled(int subId) {
+        enforceReadPrivilegedPermission("isIccLockEnabled");
+
+        // Now that all security checks passes, perform the operation as ourselves.
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            Phone phone = getPhone(subId);
+            if (phone != null && phone.getIccCard() != null) {
+                return phone.getIccCard().getIccLockEnabled();
+            } else {
+                return false;
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Set the ICC pin lock enabled or disabled..
+     *
+     * @return Integer.MAX_VALUE if enable/disable IccLock successfully. If failed it will return
+     * 0 or a positive integer as the attempts remaining value.
+     *
+     */
+    @Override
+    public int setIccLockEnabled(int subId, boolean enabled, String password) {
+        enforceModifyPermission();
+
+        Phone phone = getPhone(subId);
+        if (phone == null) {
+            return 0;
+        }
+        // Now that all security checks passes, perform the operation as ourselves.
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            int attemptsRemaining = (int) sendRequest(CMD_SET_ICC_LOCK_ENABLED,
+                    new Pair<Boolean, String>(enabled, password), phone, null);
+            return attemptsRemaining;
+
+        } catch (Exception e) {
+            Log.e(LOG_TAG, "setIccLockEnabled. Exception e =" + e);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+        return 0;
+    }
+
+    /**
+     * Change the ICC password used in ICC pin lock.
+     *
+     * @return Integer.MAX_VALUE if enable/disable IccLock successfully. If failed it will return
+     * 0 or a positive integer as the attempts remaining value.
+     *
+     */
+    @Override
+    public int changeIccLockPassword(int subId, String oldPassword, String newPassword) {
+        enforceModifyPermission();
+
+        Phone phone = getPhone(subId);
+        if (phone == null) {
+            return 0;
+        }
+        // Now that all security checks passes, perform the operation as ourselves.
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            int attemptsRemaining = (int) sendRequest(CMD_CHANGE_ICC_LOCK_PASSWORD,
+                    new Pair<String, String>(oldPassword, newPassword), phone, null);
+            return attemptsRemaining;
+
+        } catch (Exception e) {
+            Log.e(LOG_TAG, "changeIccLockPassword. Exception e =" + e);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+        return 0;
+    }
 }
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index 9835ba1..20a818e 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -31,7 +31,7 @@
 import android.telecom.VideoProfile;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
 import android.text.TextUtils;
 import android.util.Log;
@@ -701,7 +701,7 @@
      * {@code false} otherwise.
      */
     public static boolean isPhoneAccountActive(SubscriptionManager sm, PhoneAccountHandle handle) {
-        return sm.getActiveSubscriptionInfoForIccIndex(handle.getId()) != null;
+        return sm.getActiveSubscriptionInfoForIcc(handle.getId()) != null;
     }
 
     private static ComponentName getPstnConnectionServiceName() {
diff --git a/src/com/android/phone/ServiceStateProvider.java b/src/com/android/phone/ServiceStateProvider.java
new file mode 100644
index 0000000..a7d27d5
--- /dev/null
+++ b/src/com/android/phone/ServiceStateProvider.java
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import static android.provider.Telephony.ServiceStateTable;
+import static android.provider.Telephony.ServiceStateTable.CONTENT_URI;
+import static android.provider.Telephony.ServiceStateTable.IS_MANUAL_NETWORK_SELECTION;
+import static android.provider.Telephony.ServiceStateTable.VOICE_REG_STATE;
+import static android.provider.Telephony.ServiceStateTable.getUriForSubscriptionId;
+import static android.provider.Telephony.ServiceStateTable.getUriForSubscriptionIdAndField;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.database.MatrixCursor.RowBuilder;
+import android.net.Uri;
+import android.os.Parcel;
+import android.telephony.ServiceState;
+import android.telephony.SubscriptionManager;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * The class to provide base facility to access ServiceState related content,
+ * which is stored in a SQLite database.
+ */
+public class ServiceStateProvider extends ContentProvider {
+    private static final String TAG = "ServiceStateProvider";
+
+    public static final String AUTHORITY = ServiceStateTable.AUTHORITY;
+    public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
+
+    /**
+     * The current service state.
+     *
+     * This is the entire {@link ServiceState} object in byte array.
+     *
+     * @hide
+     */
+    public static final String SERVICE_STATE = "service_state";
+
+    /**
+     * An integer value indicating the current data service state.
+     * <p>
+     * Valid values: {@link ServiceState#STATE_IN_SERVICE},
+     * {@link ServiceState#STATE_OUT_OF_SERVICE}, {@link ServiceState#STATE_EMERGENCY_ONLY},
+     * {@link ServiceState#STATE_POWER_OFF}.
+     * <p>
+     * This is the same as {@link ServiceState#getDataRegState()}.
+     * @hide
+     */
+    public static final String DATA_REG_STATE = "data_reg_state";
+
+    /**
+     * An integer value indicating the current voice roaming type.
+     * <p>
+     * This is the same as {@link ServiceState#getVoiceRoamingType()}.
+     * @hide
+     */
+    public static final String VOICE_ROAMING_TYPE = "voice_roaming_type";
+
+    /**
+     * An integer value indicating the current data roaming type.
+     * <p>
+     * This is the same as {@link ServiceState#getDataRoamingType()}.
+     * @hide
+     */
+    public static final String DATA_ROAMING_TYPE = "data_roaming_type";
+
+    /**
+     * The current registered voice network operator name in long alphanumeric format.
+     * <p>
+     * This is the same as {@link ServiceState#getOperatorAlphaLong()}.
+     * @hide
+     */
+    public static final String VOICE_OPERATOR_ALPHA_LONG = "voice_operator_alpha_long";
+
+    /**
+     * The current registered operator name in short alphanumeric format.
+     * <p>
+     * In GSM/UMTS, short format can be up to 8 characters long. The current registered voice
+     * network operator name in long alphanumeric format.
+     * <p>
+     * This is the same as {@link ServiceState#getOperatorAlphaShort()}.
+     * @hide
+     */
+    public static final String VOICE_OPERATOR_ALPHA_SHORT = "voice_operator_alpha_short";
+
+    /**
+     * The current registered operator numeric id.
+     * <p>
+     * In GSM/UMTS, numeric format is 3 digit country code plus 2 or 3 digit
+     * network code.
+     * <p>
+     * This is the same as {@link ServiceState#getOperatorNumeric()}.
+     */
+    public static final String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric";
+
+    /**
+     * The current registered data network operator name in long alphanumeric format.
+     * <p>
+     * This is the same as {@link ServiceState#getOperatorAlphaLong()}.
+     * @hide
+     */
+    public static final String DATA_OPERATOR_ALPHA_LONG = "data_operator_alpha_long";
+
+    /**
+     * The current registered data network operator name in short alphanumeric format.
+     * <p>
+     * This is the same as {@link ServiceState#getOperatorAlphaShort()}.
+     * @hide
+     */
+    public static final String DATA_OPERATOR_ALPHA_SHORT = "data_operator_alpha_short";
+
+    /**
+     * The current registered data network operator numeric id.
+     * <p>
+     * This is the same as {@link ServiceState#getOperatorNumeric()}.
+     * @hide
+     */
+    public static final String DATA_OPERATOR_NUMERIC = "data_operator_numeric";
+
+    /**
+     * This is the same as {@link ServiceState#getRilVoiceRadioTechnology()}.
+     * @hide
+     */
+    public static final String RIL_VOICE_RADIO_TECHNOLOGY = "ril_voice_radio_technology";
+
+    /**
+     * This is the same as {@link ServiceState#getRilDataRadioTechnology()}.
+     * @hide
+     */
+    public static final String RIL_DATA_RADIO_TECHNOLOGY = "ril_data_radio_technology";
+
+    /**
+     * This is the same as {@link ServiceState#getCssIndicator()}.
+     * @hide
+     */
+    public static final String CSS_INDICATOR = "css_indicator";
+
+    /**
+     * This is the same as {@link ServiceState#getCdmaNetworkId()}.
+     * @hide
+     */
+    public static final String NETWORK_ID = "network_id";
+
+    /**
+     * This is the same as {@link ServiceState#getCdmaSystemId()}.
+     * @hide
+     */
+    public static final String SYSTEM_ID = "system_id";
+
+    /**
+     * This is the same as {@link ServiceState#getCdmaRoamingIndicator()}.
+     * @hide
+     */
+    public static final String CDMA_ROAMING_INDICATOR = "cdma_roaming_indicator";
+
+    /**
+     * This is the same as {@link ServiceState#getCdmaDefaultRoamingIndicator()}.
+     * @hide
+     */
+    public static final String CDMA_DEFAULT_ROAMING_INDICATOR =
+            "cdma_default_roaming_indicator";
+
+    /**
+     * This is the same as {@link ServiceState#getCdmaEriIconIndex()}.
+     * @hide
+     */
+    public static final String CDMA_ERI_ICON_INDEX = "cdma_eri_icon_index";
+
+    /**
+     * This is the same as {@link ServiceState#getCdmaEriIconMode()}.
+     * @hide
+     */
+    public static final String CDMA_ERI_ICON_MODE = "cdma_eri_icon_mode";
+
+    /**
+     * This is the same as {@link ServiceState#isEmergencyOnly()}.
+     * @hide
+     */
+    public static final String IS_EMERGENCY_ONLY = "is_emergency_only";
+
+    /**
+     * This is the same as {@link ServiceState#getDataRoamingFromRegistration()}.
+     * @hide
+     */
+    public static final String IS_DATA_ROAMING_FROM_REGISTRATION =
+            "is_data_roaming_from_registration";
+
+    /**
+     * This is the same as {@link ServiceState#isUsingCarrierAggregation()}.
+     * @hide
+     */
+    public static final String IS_USING_CARRIER_AGGREGATION = "is_using_carrier_aggregation";
+
+    /**
+     * The current registered raw data network operator name in long alphanumeric format.
+     * <p>
+     * This is the same as {@link ServiceState#getOperatorAlphaLongRaw()}.
+     * @hide
+     */
+    public static final String OPERATOR_ALPHA_LONG_RAW = "operator_alpha_long_raw";
+
+    /**
+     * The current registered raw data network operator name in short alphanumeric format.
+     * <p>
+     * This is the same as {@link ServiceState#getOperatorAlphaShortRaw()}.
+     * @hide
+     */
+    public static final String OPERATOR_ALPHA_SHORT_RAW = "operator_alpha_short_raw";
+
+    private final HashMap<Integer, ServiceState> mServiceStates = new HashMap<>();
+    private static final String[] sColumns = {
+        VOICE_REG_STATE,
+        DATA_REG_STATE,
+        VOICE_ROAMING_TYPE,
+        DATA_ROAMING_TYPE,
+        VOICE_OPERATOR_ALPHA_LONG,
+        VOICE_OPERATOR_ALPHA_SHORT,
+        VOICE_OPERATOR_NUMERIC,
+        DATA_OPERATOR_ALPHA_LONG,
+        DATA_OPERATOR_ALPHA_SHORT,
+        DATA_OPERATOR_NUMERIC,
+        IS_MANUAL_NETWORK_SELECTION,
+        RIL_VOICE_RADIO_TECHNOLOGY,
+        RIL_DATA_RADIO_TECHNOLOGY,
+        CSS_INDICATOR,
+        NETWORK_ID,
+        SYSTEM_ID,
+        CDMA_ROAMING_INDICATOR,
+        CDMA_DEFAULT_ROAMING_INDICATOR,
+        CDMA_ERI_ICON_INDEX,
+        CDMA_ERI_ICON_MODE,
+        IS_EMERGENCY_ONLY,
+        IS_USING_CARRIER_AGGREGATION,
+        OPERATOR_ALPHA_LONG_RAW,
+        OPERATOR_ALPHA_SHORT_RAW,
+    };
+
+    @Override
+    public boolean onCreate() {
+        return true;
+    }
+
+    /**
+     * Returns the {@link ServiceState} information on specified subscription.
+     *
+     * @param subId whose subscriber id is returned
+     * @return the {@link ServiceState} information on specified subscription.
+     */
+    @VisibleForTesting
+    public ServiceState getServiceState(int subId) {
+        return mServiceStates.get(subId);
+    }
+
+    /**
+     * Returns the system's default subscription id.
+     *
+     * @return the "system" default subscription id.
+     */
+    @VisibleForTesting
+    public int getDefaultSubId() {
+        return SubscriptionManager.getDefaultSubscriptionId();
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        if (isPathPrefixMatch(uri, CONTENT_URI)) {
+            // Parse the subId
+            int subId = 0;
+            try {
+                subId = Integer.parseInt(uri.getLastPathSegment());
+            } catch (NumberFormatException e) {
+                Log.e(TAG, "insert: no subId provided in uri");
+                throw e;
+            }
+            Log.d(TAG, "subId=" + subId);
+
+            // handle DEFAULT_SUBSCRIPTION_ID
+            if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
+                subId = getDefaultSubId();
+            }
+
+            final Parcel p = Parcel.obtain();
+            final byte[] rawBytes = values.getAsByteArray(SERVICE_STATE);
+            p.unmarshall(rawBytes, 0, rawBytes.length);
+            p.setDataPosition(0);
+
+            // create the new service state
+            final ServiceState newSS = ServiceState.CREATOR.createFromParcel(p);
+
+            // notify listeners
+            // if ss is null (e.g. first service state update) we will notify for all fields
+            ServiceState ss = getServiceState(subId);
+            notifyChangeForSubIdAndField(getContext(), ss, newSS, subId);
+            notifyChangeForSubId(getContext(), ss, newSS, subId);
+
+            // store the new service state
+            mServiceStates.put(subId, newSS);
+            return uri;
+        }
+        return null;
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        throw new RuntimeException("Not supported");
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        throw new RuntimeException("Not supported");
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        throw new RuntimeException("Not supported");
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        if (!isPathPrefixMatch(uri, CONTENT_URI)) {
+            throw new IllegalArgumentException("Invalid URI: " + uri);
+        } else {
+            // Parse the subId
+            int subId = 0;
+            try {
+                subId = Integer.parseInt(uri.getLastPathSegment());
+            } catch (NumberFormatException e) {
+                Log.d(TAG, "query: no subId provided in uri, using default.");
+                subId = getDefaultSubId();
+            }
+            Log.d(TAG, "subId=" + subId);
+
+            // handle DEFAULT_SUBSCRIPTION_ID
+            if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
+                subId = getDefaultSubId();
+            }
+
+            // Get the service state
+            ServiceState ss = getServiceState(subId);
+            if (ss == null) {
+                Log.d(TAG, "returning null");
+                return null;
+            }
+
+            // Build the result
+            final int voice_reg_state = ss.getState();
+            final int data_reg_state = ss.getDataRegistrationState();
+            final int voice_roaming_type = ss.getVoiceRoamingType();
+            final int data_roaming_type = ss.getDataRoamingType();
+            final String voice_operator_alpha_long = ss.getOperatorAlphaLong();
+            final String voice_operator_alpha_short = ss.getOperatorAlphaShort();
+            final String voice_operator_numeric = ss.getOperatorNumeric();
+            final String data_operator_alpha_long = ss.getOperatorAlphaLong();
+            final String data_operator_alpha_short = ss.getOperatorAlphaShort();
+            final String data_operator_numeric = ss.getOperatorNumeric();
+            final int is_manual_network_selection = (ss.getIsManualSelection()) ? 1 : 0;
+            final int ril_voice_radio_technology = ss.getRilVoiceRadioTechnology();
+            final int ril_data_radio_technology = ss.getRilDataRadioTechnology();
+            final int css_indicator = ss.getCssIndicator();
+            final int network_id = ss.getCdmaNetworkId();
+            final int system_id = ss.getCdmaSystemId();
+            final int cdma_roaming_indicator = ss.getCdmaRoamingIndicator();
+            final int cdma_default_roaming_indicator = ss.getCdmaDefaultRoamingIndicator();
+            final int cdma_eri_icon_index = ss.getCdmaEriIconIndex();
+            final int cdma_eri_icon_mode = ss.getCdmaEriIconMode();
+            final int is_emergency_only = (ss.isEmergencyOnly()) ? 1 : 0;
+            final int is_using_carrier_aggregation = (ss.isUsingCarrierAggregation()) ? 1 : 0;
+            final String operator_alpha_long_raw = ss.getOperatorAlphaLongRaw();
+            final String operator_alpha_short_raw = ss.getOperatorAlphaShortRaw();
+
+            return buildSingleRowResult(projection, sColumns, new Object[] {
+                    voice_reg_state,
+                    data_reg_state,
+                    voice_roaming_type,
+                    data_roaming_type,
+                    voice_operator_alpha_long,
+                    voice_operator_alpha_short,
+                    voice_operator_numeric,
+                    data_operator_alpha_long,
+                    data_operator_alpha_short,
+                    data_operator_numeric,
+                    is_manual_network_selection,
+                    ril_voice_radio_technology,
+                    ril_data_radio_technology,
+                    css_indicator,
+                    network_id,
+                    system_id,
+                    cdma_roaming_indicator,
+                    cdma_default_roaming_indicator,
+                    cdma_eri_icon_index,
+                    cdma_eri_icon_mode,
+                    is_emergency_only,
+                    is_using_carrier_aggregation,
+                    operator_alpha_long_raw,
+                    operator_alpha_short_raw,
+            });
+        }
+    }
+
+    private static Cursor buildSingleRowResult(String[] projection, String[] availableColumns,
+            Object[] data) {
+        if (projection == null) {
+            projection = availableColumns;
+        }
+        final MatrixCursor c = new MatrixCursor(projection, 1);
+        final RowBuilder row = c.newRow();
+        for (int i = 0; i < c.getColumnCount(); i++) {
+            final String columnName = c.getColumnName(i);
+            boolean found = false;
+            for (int j = 0; j < availableColumns.length; j++) {
+                if (availableColumns[j].equals(columnName)) {
+                    row.add(data[j]);
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                throw new IllegalArgumentException("Invalid column " + projection[i]);
+            }
+        }
+        return c;
+    }
+
+    /**
+     * Notify interested apps that certain fields of the ServiceState have changed.
+     *
+     * Apps which want to wake when specific fields change can use
+     * JobScheduler's TriggerContentUri.  This replaces the waking functionality of the implicit
+     * broadcast of ACTION_SERVICE_STATE_CHANGED for apps targeting version O.
+     *
+     * We will only notify for certain fields. This is an intentional change from the behavior of
+     * the broadcast. Listeners will be notified when the voice or data registration state or
+     * roaming type changes.
+     */
+    @VisibleForTesting
+    public static void notifyChangeForSubIdAndField(Context context, ServiceState oldSS,
+            ServiceState newSS, int subId) {
+        final boolean firstUpdate = (oldSS == null) ? true : false;
+
+        // for every field, if the field has changed values, notify via the provider
+        if (firstUpdate || voiceRegStateChanged(oldSS, newSS)) {
+            context.getContentResolver().notifyChange(
+                    getUriForSubscriptionIdAndField(subId, VOICE_REG_STATE),
+                    /* observer= */ null, /* syncToNetwork= */ false);
+        }
+        if (firstUpdate || dataRegStateChanged(oldSS, newSS)) {
+            context.getContentResolver().notifyChange(
+                    getUriForSubscriptionIdAndField(subId, DATA_REG_STATE), null, false);
+        }
+        if (firstUpdate || voiceRoamingTypeChanged(oldSS, newSS)) {
+            context.getContentResolver().notifyChange(
+                    getUriForSubscriptionIdAndField(subId, VOICE_ROAMING_TYPE), null, false);
+        }
+        if (firstUpdate || dataRoamingTypeChanged(oldSS, newSS)) {
+            context.getContentResolver().notifyChange(
+                    getUriForSubscriptionIdAndField(subId, DATA_ROAMING_TYPE), null, false);
+        }
+    }
+
+    private static boolean voiceRegStateChanged(ServiceState oldSS, ServiceState newSS) {
+        return oldSS.getState() != newSS.getState();
+    }
+
+    private static boolean dataRegStateChanged(ServiceState oldSS, ServiceState newSS) {
+        return oldSS.getDataRegistrationState() != newSS.getDataRegistrationState();
+    }
+
+    private static boolean voiceRoamingTypeChanged(ServiceState oldSS, ServiceState newSS) {
+        return oldSS.getVoiceRoamingType() != newSS.getVoiceRoamingType();
+    }
+
+    private static boolean dataRoamingTypeChanged(ServiceState oldSS, ServiceState newSS) {
+        return oldSS.getDataRoamingType() != newSS.getDataRoamingType();
+    }
+
+    /**
+     * Notify interested apps that the ServiceState has changed.
+     *
+     * Apps which want to wake when any field in the ServiceState has changed can use
+     * JobScheduler's TriggerContentUri.  This replaces the waking functionality of the implicit
+     * broadcast of ACTION_SERVICE_STATE_CHANGED for apps targeting version O.
+     *
+     * We will only notify for certain fields. This is an intentional change from the behavior of
+     * the broadcast. Listeners will only be notified when the voice/data registration state or
+     * roaming type changes.
+     */
+    @VisibleForTesting
+    public static void notifyChangeForSubId(Context context, ServiceState oldSS, ServiceState newSS,
+            int subId) {
+        // if the voice or data registration or roaming state field has changed values, notify via
+        // the provider.
+        // If oldSS is null and newSS is not (e.g. first update of service state) this will also
+        // notify
+        if (oldSS == null || voiceRegStateChanged(oldSS, newSS) || dataRegStateChanged(oldSS, newSS)
+                || voiceRoamingTypeChanged(oldSS, newSS) || dataRoamingTypeChanged(oldSS, newSS)) {
+            context.getContentResolver().notifyChange(getUriForSubscriptionId(subId), null, false);
+        }
+    }
+
+    /**
+     * Test if this is a path prefix match against the given Uri. Verifies that
+     * scheme, authority, and atomic path segments match.
+     *
+     * Copied from frameworks/base/core/java/android/net/Uri.java
+     */
+    private boolean isPathPrefixMatch(Uri uriA, Uri uriB) {
+        if (!Objects.equals(uriA.getScheme(), uriB.getScheme())) return false;
+        if (!Objects.equals(uriA.getAuthority(), uriB.getAuthority())) return false;
+
+        List<String> segA = uriA.getPathSegments();
+        List<String> segB = uriB.getPathSegments();
+
+        final int size = segB.size();
+        if (segA.size() < size) return false;
+
+        for (int i = 0; i < size; i++) {
+            if (!Objects.equals(segA.get(i), segB.get(i))) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Used to insert a ServiceState into the ServiceStateProvider as a ContentValues instance.
+     *
+     * @param state the ServiceState to convert into ContentValues
+     * @return the convertedContentValues instance
+     * @hide
+     */
+    public static ContentValues getContentValuesForServiceState(ServiceState state) {
+        ContentValues values = new ContentValues();
+        final Parcel p = Parcel.obtain();
+        state.writeToParcel(p, 0);
+        // Turn the parcel to byte array. Safe to do this because the content values were never
+        // written into a persistent storage. ServiceStateProvider keeps values in the memory.
+        values.put(SERVICE_STATE, p.marshall());
+        return values;
+    }
+}
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index 0806fd1..53b3356 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -26,6 +26,7 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.emergency.EmergencyNumber;
+import android.telephony.ims.feature.ImsFeature;
 import android.util.Log;
 
 import com.android.internal.telephony.ITelephony;
@@ -35,6 +36,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.TreeSet;
 
@@ -180,13 +182,15 @@
     private void onHelpIms() {
         PrintWriter pw = getOutPrintWriter();
         pw.println("IMS Commands:");
-        pw.println("  ims set-ims-service [-s SLOT_ID] (-c | -d) PACKAGE_NAME");
+        pw.println("  ims set-ims-service [-s SLOT_ID] (-c | -d | -f) PACKAGE_NAME");
         pw.println("    Sets the ImsService defined in PACKAGE_NAME to to be the bound");
         pw.println("    ImsService. Options are:");
         pw.println("      -s: the slot ID that the ImsService should be bound for. If no option");
         pw.println("          is specified, it will choose the default voice SIM slot.");
         pw.println("      -c: Override the ImsService defined in the carrier configuration.");
         pw.println("      -d: Override the ImsService defined in the device overlay.");
+        pw.println("      -f: Set the feature that this override if for, if no option is");
+        pw.println("          specified, the new package name will be used for all features.");
         pw.println("  ims get-ims-service [-s SLOT_ID] [-c | -d]");
         pw.println("    Gets the package name of the currently defined ImsService.");
         pw.println("    Options are:");
@@ -194,6 +198,8 @@
         pw.println("          is specified, it will choose the default voice SIM slot.");
         pw.println("      -c: The ImsService defined as the carrier configured ImsService.");
         pw.println("      -c: The ImsService defined as the device default ImsService.");
+        pw.println("      -f: The feature type that the query will be requested for. If none is");
+        pw.println("          specified, the returned package name will correspond to MMTEL.");
         pw.println("  ims enable [-s SLOT_ID]");
         pw.println("    enables IMS for the SIM slot specified, or for the default voice SIM slot");
         pw.println("    if none is specified.");
@@ -444,6 +450,7 @@
         PrintWriter errPw = getErrPrintWriter();
         int slotId = getDefaultSlot();
         Boolean isCarrierService = null;
+        List<Integer> featuresList = new ArrayList<>();
 
         String opt;
         while ((opt = getNextOption()) != null) {
@@ -465,6 +472,26 @@
                     isCarrierService = false;
                     break;
                 }
+                case "-f": {
+                    String featureString = getNextArgRequired();
+                    String[] features = featureString.split(",");
+                    for (int i = 0; i < features.length; i++) {
+                        try {
+                            Integer result = Integer.parseInt(features[i]);
+                            if (result < ImsFeature.FEATURE_EMERGENCY_MMTEL
+                                    || result >= ImsFeature.FEATURE_MAX) {
+                                errPw.println("ims set-ims-service -f " + result
+                                        + " is an invalid feature.");
+                                return -1;
+                            }
+                            featuresList.add(result);
+                        } catch (NumberFormatException e) {
+                            errPw.println("ims set-ims-service -f tried to parse " + features[i]
+                                            + " as an integer.");
+                            return -1;
+                        }
+                    }
+                }
             }
         }
         // Mandatory param, either -c or -d
@@ -479,16 +506,24 @@
             if (packageName == null) {
                 packageName = "";
             }
-            boolean result = mInterface.setImsService(slotId, isCarrierService, packageName);
+            int[] featureArray = new int[featuresList.size()];
+            for (int i = 0; i < featuresList.size(); i++) {
+                featureArray[i] = featuresList.get(i);
+            }
+            boolean result = mInterface.setBoundImsServiceOverride(slotId, isCarrierService,
+                    featureArray, packageName);
             if (VDBG) {
                 Log.v(LOG_TAG, "ims set-ims-service -s " + slotId + " "
-                        + (isCarrierService ? "-c " : "-d ") + packageName + ", result=" + result);
+                        + (isCarrierService ? "-c " : "-d ")
+                        + "-f " + featuresList + " "
+                        + packageName + ", result=" + result);
             }
             getOutPrintWriter().println(result);
         } catch (RemoteException e) {
             Log.w(LOG_TAG, "ims set-ims-service -s " + slotId + " "
-                    + (isCarrierService ? "-c " : "-d ") + packageName + ", error"
-                    + e.getMessage());
+                    + (isCarrierService ? "-c " : "-d ")
+                    + "-f " + featuresList + " "
+                    + packageName + ", error" + e.getMessage());
             errPw.println("Exception: " + e.getMessage());
             return -1;
         }
@@ -500,6 +535,7 @@
         PrintWriter errPw = getErrPrintWriter();
         int slotId = getDefaultSlot();
         Boolean isCarrierService = null;
+        Integer featureType = ImsFeature.FEATURE_MMTEL;
 
         String opt;
         while ((opt = getNextOption()) != null) {
@@ -521,23 +557,38 @@
                     isCarrierService = false;
                     break;
                 }
+                case "-f": {
+                    try {
+                        featureType = Integer.parseInt(getNextArg());
+                    } catch (NumberFormatException e) {
+                        errPw.println("ims get-ims-service -f requires valid integer as feature.");
+                        return -1;
+                    }
+                    if (featureType < ImsFeature.FEATURE_EMERGENCY_MMTEL
+                            || featureType >= ImsFeature.FEATURE_MAX) {
+                        errPw.println("ims get-ims-service -f invalid feature.");
+                        return -1;
+                    }
+                }
             }
         }
         // Mandatory param, either -c or -d
         if (isCarrierService == null) {
-            errPw.println("ims set-ims-service requires either \"-c\" or \"-d\" to be set.");
+            errPw.println("ims get-ims-service requires either \"-c\" or \"-d\" to be set.");
             return -1;
         }
 
         String result;
         try {
-            result = mInterface.getImsService(slotId, isCarrierService);
+            result = mInterface.getBoundImsServicePackage(slotId, isCarrierService, featureType);
         } catch (RemoteException e) {
             return -1;
         }
         if (VDBG) {
             Log.v(LOG_TAG, "ims get-ims-service -s " + slotId + " "
-                    + (isCarrierService ? "-c " : "-d ") + ", returned: " + result);
+                    + (isCarrierService ? "-c " : "-d ")
+                    + (featureType != null ? ("-f " + featureType) : "") + " , returned: "
+                    + result);
         }
         getOutPrintWriter().println(result);
         return 0;
diff --git a/src/com/android/phone/TimeConsumingPreferenceActivity.java b/src/com/android/phone/TimeConsumingPreferenceActivity.java
index 8c5ae6d..3b5fe21 100644
--- a/src/com/android/phone/TimeConsumingPreferenceActivity.java
+++ b/src/com/android/phone/TimeConsumingPreferenceActivity.java
@@ -187,6 +187,11 @@
     @Override
     public void onError(Preference preference, int error) {
         if (DBG) dumpState();
+        if (!preference.isEnabled()) {
+            Log.i(LOG_TAG, "onError, skipped duplicated error popup");
+            return;
+        }
+
         Log.i(LOG_TAG, "onError, preference=" + preference.getKey() + ", error=" + error);
 
         if (mIsForeground) {
diff --git a/src/com/android/phone/settings/AccessibilitySettingsFragment.java b/src/com/android/phone/settings/AccessibilitySettingsFragment.java
index c9aa630..e31de64 100644
--- a/src/com/android/phone/settings/AccessibilitySettingsFragment.java
+++ b/src/com/android/phone/settings/AccessibilitySettingsFragment.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.media.AudioManager;
 import android.os.Bundle;
+import android.os.PersistableBundle;
 import android.preference.Preference;
 import android.preference.PreferenceFragment;
 import android.preference.PreferenceScreen;
@@ -64,12 +65,9 @@
                 // support multi sim configuration.
                 TelephonyManager telephonyManager =
                         (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
-                final boolean isVolteTtySupported = getVolteTtySupported();
-                final boolean isVolteCurrentlyEnabled =
-                        ImsManager.isVolteEnabledByPlatform(mContext);
-                pref.setEnabled((isVolteTtySupported && isVolteCurrentlyEnabled &&
-                        !isVideoCallOrConferenceInProgress()) ||
-                        (telephonyManager.getCallState() == TelephonyManager.CALL_STATE_IDLE));
+                final boolean isVolteTtySupported = isVolteTtySupportedInAnySlot();
+                pref.setEnabled((isVolteTtySupported && !isVideoCallOrConferenceInProgress())
+                        || (telephonyManager.getCallState() == TelephonyManager.CALL_STATE_IDLE));
             }
         }
     };
@@ -166,17 +164,55 @@
             int rttMode = mButtonRtt.isChecked() ? 1 : 0;
             Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.RTT_CALLING_MODE,
                     rttMode);
+            // Update RTT config with IMS Manager if the always-on carrier config isn't set to true.
+            CarrierConfigManager configManager = (CarrierConfigManager) mContext.getSystemService(
+                            Context.CARRIER_CONFIG_SERVICE);
+            for (int subId : SubscriptionController.getInstance().getActiveSubIdList(true)) {
+                if (!configManager.getConfigForSubId(subId).getBoolean(
+                        CarrierConfigManager.KEY_IGNORE_RTT_MODE_SETTING_BOOL, false)) {
+                    int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
+                    ImsManager imsManager = ImsManager.getInstance(getContext(), phoneId);
+                    imsManager.setRttEnabled(mButtonRtt.isChecked());
+                }
+            }
             return true;
         }
 
         return false;
     }
 
-    private boolean getVolteTtySupported() {
+    private boolean isVolteTtySupportedInAnySlot() {
+        final Phone[] phones = PhoneFactory.getPhones();
+        if (phones == null) {
+            if (DBG) Log.d(LOG_TAG, "isVolteTtySupportedInAnySlot: No phones found.");
+            return false;
+        }
+
         CarrierConfigManager configManager =
                 (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
-        return configManager.getConfig().getBoolean(
-                CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL);
+        for (Phone phone : phones) {
+            // Check if this phone supports VoLTE.
+            ImsManager imsManager = ImsManager.getInstance(mContext, phone.getPhoneId());
+            boolean volteEnabled = false;
+            if (imsManager != null) {
+                volteEnabled = imsManager.isVolteEnabledByPlatform();
+            }
+
+            // Check if this phone suports VoLTE TTY.
+            boolean volteTtySupported = false;
+            PersistableBundle carrierConfig = configManager.getConfigForSubId(phone.getSubId());
+            if (carrierConfig != null) {
+                volteTtySupported = carrierConfig.getBoolean(
+                        CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL);
+            }
+
+            if (volteEnabled && volteTtySupported) {
+                // VoLTE TTY is supported on this phone that also suports VoLTE.
+                return true;
+            }
+        }
+        // VoLTE TTY was not supported on any phone that also supports VoLTE.
+        return false;
     }
 
     private boolean isVideoCallOrConferenceInProgress() {
diff --git a/src/com/android/phone/settings/CallForwardInfoUtil.java b/src/com/android/phone/settings/CallForwardInfoUtil.java
index 1983fab..b963df8 100644
--- a/src/com/android/phone/settings/CallForwardInfoUtil.java
+++ b/src/com/android/phone/settings/CallForwardInfoUtil.java
@@ -82,6 +82,7 @@
         phone.setCallForwardingOption(commandInterfaceCfAction,
                 info.reason,
                 info.number,
+                info.serviceClass,
                 info.timeSeconds,
                 message);
     }
@@ -93,10 +94,12 @@
      */
     public static CallForwardInfo getCallForwardInfo(CallForwardInfo[] infos, int reason) {
         CallForwardInfo info = null;
-        for (int i = 0 ; i < infos.length; i++) {
-            if (isServiceClassVoice(infos[i])) {
-                info = infos[i];
-                break;
+        if (infos != null) {
+            for (int i = 0 ; i < infos.length; i++) {
+                if (isServiceClassVoice(infos[i])) {
+                    info = infos[i];
+                    break;
+                }
             }
         }
 
diff --git a/src/com/android/phone/settings/RadioInfo.java b/src/com/android/phone/settings/RadioInfo.java
index ce5b839..31b7a9e 100644
--- a/src/com/android/phone/settings/RadioInfo.java
+++ b/src/com/android/phone/settings/RadioInfo.java
@@ -111,28 +111,40 @@
     private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
 
     private static final String[] PREFERRED_NETWORK_LABELS = {
-            "WCDMA preferred",
+            "GSM/WCDMA preferred",
             "GSM only",
             "WCDMA only",
-            "GSM auto (PRL)",
-            "CDMA auto (PRL)",
+            "GSM/WCDMA auto (PRL)",
+            "CDMA/EvDo auto (PRL)",
             "CDMA only",
             "EvDo only",
-            "Global auto (PRL)",
-            "LTE/CDMA auto (PRL)",
-            "LTE/UMTS auto (PRL)",
-            "LTE/CDMA/UMTS auto (PRL)",
+            "CDMA/EvDo/GSM/WCDMA (PRL)",
+            "CDMA + LTE/EvDo (PRL)",
+            "GSM/WCDMA/LTE (PRL)",
+            "LTE/CDMA/EvDo/GSM/WCDMA (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",
+            "TDSCDMA only",
+            "TDSCDMA/WCDMA",
+            "LTE/TDSCDMA",
+            "TDSCDMA/GSM",
+            "LTE/TDSCDMA/GSM",
+            "TDSCDMA/GSM/WCDMA",
+            "LTE/TDSCDMA/WCDMA",
+            "LTE/TDSCDMA/GSM/WCDMA",
+            "TDSCDMA/CDMA/EvDo/GSM/WCDMA ",
+            "LTE/TDSCDMA/CDMA/EvDo/GSM/WCDMA",
+            "NR only",
+            "NR/LTE",
+            "NR/LTE/CDMA/EvDo",
+            "NR/LTE/GSM/WCDMA",
+            "NR/LTE/CDMA/EvDo/GSM/WCDMA",
+            "NR/LTE/WCDMA",
+            "NR/LTE/TDSCDMA",
+            "NR/LTE/TDSCDMA/GSM",
+            "NR/LTE/TDSCDMA/WCDMA",
+            "NR/LTE/TDSCDMA/GSM/WCDMA",
+            "NR/LTE/TDSCDMA/CDMA/EvDo/GSM/WCDMA",
             "Unknown"
     };
 
@@ -1437,8 +1449,18 @@
     OnCheckedChangeListener mRadioPowerOnChangeListener = new OnCheckedChangeListener() {
         @Override
         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-            log("toggle radio power: currently " + (isRadioOn() ? "on" : "off"));
-            mPhone.setRadioPower(isChecked);
+            // TODO: b/145681511. Within current design, radio power on all of the phones need
+            // to be controlled at the same time.
+            Phone[] phones = PhoneFactory.getPhones();
+            if (phones == null) {
+                return;
+            }
+            log("toggle radio power: phone*" + phones.length + " " + (isRadioOn() ? "on" : "off"));
+            for (int phoneIndex = 0; phoneIndex < phones.length; phoneIndex++) {
+                if (phones[phoneIndex] != null) {
+                    phones[phoneIndex].setRadioPower(isChecked);
+                }
+            }
         }
     };
 
@@ -1706,7 +1728,7 @@
             mQueuedWork.execute(new Runnable() {
                 public void run() {
                     mTelephonyManager.setOpportunisticNetworkState(state);
-                    mCbrsDataSwitch.setChecked(getCbrsDataState());
+                    mHandler.post(() -> mCbrsDataSwitch.setChecked(getCbrsDataState()));
                 }
             });
         }
diff --git a/src/com/android/phone/settings/SuppServicesUiUtil.java b/src/com/android/phone/settings/SuppServicesUiUtil.java
index 4e9841f..4f1a79f 100644
--- a/src/com/android/phone/settings/SuppServicesUiUtil.java
+++ b/src/com/android/phone/settings/SuppServicesUiUtil.java
@@ -84,7 +84,7 @@
                 .create();
     }
 
-    private static String makeMessage(Context context, String preferenceKey, Phone phone) {
+    public static String makeMessage(Context context, String preferenceKey, Phone phone) {
         String message = "";
         int simSlot = (phone.getPhoneId() == 0) ? 1 : 2;
         String suppServiceName = getSuppServiceName(context, preferenceKey);
diff --git a/src/com/android/phone/settings/VoicemailSettingsActivity.java b/src/com/android/phone/settings/VoicemailSettingsActivity.java
index e18dc93..66b1af9 100644
--- a/src/com/android/phone/settings/VoicemailSettingsActivity.java
+++ b/src/com/android/phone/settings/VoicemailSettingsActivity.java
@@ -43,6 +43,7 @@
 import android.widget.Toast;
 
 import com.android.internal.telephony.CallForwardInfo;
+import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.util.NotificationChannelController;
@@ -733,6 +734,7 @@
             for (int i = 0; i < mForwardingReadResults.length; i++) {
                 mPhone.getCallForwardingOption(
                         VoicemailProviderSettings.FORWARDING_SETTINGS_REASONS[i],
+                        CommandsInterface.SERVICE_CLASS_VOICE,
                         mGetOptionComplete.obtainMessage(EVENT_FORWARDING_GET_COMPLETED, i, 0));
             }
             showDialogIfForeground(VoicemailDialogUtil.VM_FWD_READING_DIALOG);
diff --git a/src/com/android/phone/settings/fdn/DeleteFdnContactScreen.java b/src/com/android/phone/settings/fdn/DeleteFdnContactScreen.java
index 92baa97..8b17cfb 100644
--- a/src/com/android/phone/settings/fdn/DeleteFdnContactScreen.java
+++ b/src/com/android/phone/settings/fdn/DeleteFdnContactScreen.java
@@ -64,7 +64,8 @@
 
         resolveIntent();
 
-        authenticatePin2();
+        // Starts PIN2 authentication only for the first time.
+        if (icicle == null) authenticatePin2();
 
         getWindow().requestFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
         setContentView(R.layout.delete_fdn_contact_screen);
diff --git a/src/com/android/phone/settings/fdn/EditFdnContactScreen.java b/src/com/android/phone/settings/fdn/EditFdnContactScreen.java
index 0eda140..140cc74 100644
--- a/src/com/android/phone/settings/fdn/EditFdnContactScreen.java
+++ b/src/com/android/phone/settings/fdn/EditFdnContactScreen.java
@@ -443,7 +443,7 @@
             }
 
             if (v == mNameField) {
-                mNumberField.requestFocus();
+                mButton.requestFocus();
             } else if (v == mNumberField) {
                 mButton.requestFocus();
             } else if (v == mButton) {
diff --git a/src/com/android/phone/settings/fdn/EditPinPreference.java b/src/com/android/phone/settings/fdn/EditPinPreference.java
index 9596f39..a9d1948 100644
--- a/src/com/android/phone/settings/fdn/EditPinPreference.java
+++ b/src/com/android/phone/settings/fdn/EditPinPreference.java
@@ -23,8 +23,6 @@
 import android.util.AttributeSet;
 import android.view.View;
 
-import com.android.phone.R;
-
 /**
  * Class similar to the com.android.settings.EditPinPreference
  * class, with a couple of modifications, including a different layout
@@ -62,27 +60,12 @@
         super(context, attrs, defStyle);
     }
 
-    /**
-     * Overridden to setup the correct dialog layout, as well as setting up
-     * other properties for the pin / puk entry field.
-     */
-    @Override
-    protected View onCreateDialogView() {
-        // set the dialog layout
-        setDialogLayoutResource(R.layout.pref_dialog_editpin);
-
-        View dialog = super.onCreateDialogView();
-
-        getEditText().setInputType(InputType.TYPE_CLASS_NUMBER |
-            InputType.TYPE_NUMBER_VARIATION_PASSWORD);
-
-        return dialog;
-    }
-
     @Override
     protected void onBindDialogView(View view) {
         super.onBindDialogView(view);
 
+        getEditText().setInputType(InputType.TYPE_CLASS_NUMBER
+                | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
         // If the layout does not contain an edittext, hide the buttons.
         shouldHideButtons = (view.findViewById(android.R.id.edit) == null);
     }
diff --git a/src/com/android/services/telephony/CdmaConference.java b/src/com/android/services/telephony/CdmaConference.java
old mode 100755
new mode 100644
index 693fd16..7458195
--- a/src/com/android/services/telephony/CdmaConference.java
+++ b/src/com/android/services/telephony/CdmaConference.java
@@ -17,6 +17,7 @@
 package com.android.services.telephony;
 
 import android.content.Context;
+import android.net.Uri;
 import android.os.PersistableBundle;
 import android.telecom.Connection;
 import android.telecom.PhoneAccountHandle;
@@ -73,6 +74,22 @@
     }
 
     @Override
+    public void onAddConferenceParticipants(List<Uri> participants) {
+        Log.e(this, new Exception(), "Adding Conference Participants not supported " +
+                " for CDMA conference call.");
+    }
+
+    @Override
+    public void onAnswer(int videoState) {
+        Log.e(this, new Exception(), "Answer not supported for CDMA conference call.");
+    }
+
+    @Override
+    public void onReject() {
+        Log.e(this, new Exception(), "Reject not supported for CDMA conference call.");
+    }
+
+    @Override
     public void onHold() {
         Log.e(this, new Exception(), "Hold not supported for CDMA conference call.");
     }
diff --git a/src/com/android/services/telephony/ConferenceParticipantConnection.java b/src/com/android/services/telephony/ConferenceParticipantConnection.java
index ed92e7f..b7ecd48 100644
--- a/src/com/android/services/telephony/ConferenceParticipantConnection.java
+++ b/src/com/android/services/telephony/ConferenceParticipantConnection.java
@@ -19,13 +19,13 @@
 import android.net.Uri;
 import android.telecom.Connection;
 import android.telecom.DisconnectCause;
-import android.telephony.Rlog;
 import android.telephony.SubscriptionInfo;
 import android.text.TextUtils;
 
 import com.android.ims.internal.ConferenceParticipant;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
+import com.android.telephony.Rlog;
 
 /**
  * Represents a participant in a conference call.
@@ -215,7 +215,7 @@
         sb.append(" connectTime:");
         sb.append(getConnectTimeMillis());
         sb.append(" connectElapsedTime:");
-        sb.append(getConnectElapsedTimeMillis());
+        sb.append(getConnectionStartElapsedRealtimeMillis());
         sb.append("]");
 
         return sb.toString();
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index 9e32f00..0da5dfc 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -847,17 +847,17 @@
             case android.telephony.DisconnectCause.UNOBTAINABLE_NUMBER:
                 return ToneGenerator.TONE_SUP_ERROR;
 
+            case android.telephony.DisconnectCause.IMS_MERGED_SUCCESSFULLY:
+                // Do not play any tones if disconnected because of a successful merge.
+                return ToneGenerator.TONE_UNKNOWN;
+
             case android.telephony.DisconnectCause.ERROR_UNSPECIFIED:
             case android.telephony.DisconnectCause.LOCAL:
             case android.telephony.DisconnectCause.NORMAL:
             case android.telephony.DisconnectCause.NORMAL_UNSPECIFIED:
             case android.telephony.DisconnectCause.VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED:
-                return ToneGenerator.TONE_PROP_PROMPT;
-
-            case android.telephony.DisconnectCause.IMS_MERGED_SUCCESSFULLY:
-                // Do not play any tones if disconnected because of a successful merge.
             default:
-                return ToneGenerator.TONE_UNKNOWN;
+                return ToneGenerator.TONE_PROP_PROMPT;
         }
     }
 }
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index 4c3f9c9..c11a1ca 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -30,7 +30,6 @@
 import android.telecom.VideoProfile;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
 import android.util.Pair;
 
 import com.android.ims.internal.ConferenceParticipant;
@@ -42,6 +41,7 @@
 import com.android.phone.PhoneGlobals;
 import com.android.phone.PhoneUtils;
 import com.android.phone.R;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -199,6 +199,18 @@
                     TelephonyConnection telephonyConnection = (TelephonyConnection) c;
                     handleConferenceParticipantsUpdate(telephonyConnection, participants);
                 }
+
+                /**
+                 * Handles request to play a ringback tone.
+                 *
+                 * @param c The connection.
+                 * @param ringback Whether the ringback tone is to be played.
+                 */
+                @Override
+                public void onRingbackRequested(android.telecom.Connection c, boolean ringback) {
+                    Log.d(this, "onRingbackRequested ringback %s", ringback ? "Y" : "N");
+                    setRingbackRequested(ringback);
+                }
             };
 
     /**
@@ -224,6 +236,11 @@
     private TelecomAccountRegistry mTelecomAccountRegistry;
 
     /**
+     * The participant with which Adhoc Conference call is getting formed.
+     */
+    private List<Uri> mParticipants;
+
+    /**
      * The known conference participant connections.  The HashMap is keyed by a Pair containing
      * the handle and endpoint Uris.
      * Access to the hashmap is protected by the {@link #mUpdateSyncRoot}.
@@ -296,10 +313,10 @@
         long connectTime = conferenceHost.getOriginalConnection().getConnectTime();
         long connectElapsedTime = conferenceHost.getOriginalConnection().getConnectTimeReal();
         setConnectionTime(connectTime);
-        setConnectionStartElapsedRealTime(connectElapsedTime);
+        setConnectionStartElapsedRealtimeMillis(connectElapsedTime);
         // Set the connectTime in the connection as well.
         conferenceHost.setConnectTimeMillis(connectTime);
-        conferenceHost.setConnectionStartElapsedRealTime(connectElapsedTime);
+        conferenceHost.setConnectionStartElapsedRealtimeMillis(connectElapsedTime);
 
         mTelephonyConnectionService = telephonyConnectionService;
         setConferenceHost(conferenceHost);
@@ -357,6 +374,10 @@
                 Connection.CAPABILITY_CAN_PAUSE_VIDEO,
                 mConferenceHost.getVideoPauseSupported() && isVideoCapable());
 
+        conferenceCapabilities = changeBitmask(conferenceCapabilities,
+                Connection.CAPABILITY_ADD_PARTICIPANT,
+                (capabilities & Connection.CAPABILITY_ADD_PARTICIPANT) != 0);
+
         return conferenceCapabilities;
     }
 
@@ -383,6 +404,10 @@
         conferenceProperties = changeBitmask(conferenceProperties,
                 Connection.PROPERTY_REMOTELY_HOSTED, !isConferenceHost());
 
+        conferenceProperties = changeBitmask(conferenceProperties,
+                Connection.PROPERTY_IS_ADHOC_CONFERENCE,
+                (properties & Connection.PROPERTY_IS_ADHOC_CONFERENCE) != 0);
+
         return conferenceProperties;
     }
 
@@ -422,6 +447,26 @@
         return VideoProfile.STATE_AUDIO_ONLY;
     }
 
+    public Connection getConferenceHost() {
+        return mConferenceHost;
+    }
+
+    /**
+     * @return The address's to which this Connection is currently communicating.
+     */
+    public final List<Uri> getParticipants() {
+        return mParticipants;
+    }
+
+    /**
+     * Sets the value of the {@link #getParticipants()}.
+     *
+     * @param address The new address's.
+     */
+    public final void setParticipants(List<Uri> address) {
+        mParticipants = address;
+    }
+
     /**
      * Invoked when the Conference and all its {@link Connection}s should be disconnected.
      * <p>
@@ -481,6 +526,41 @@
     }
 
     /**
+     * Supports adding participants to an existing conference call
+     *
+     * @param participants that are pulled to existing conference call
+     */
+    @Override
+    public void onAddConferenceParticipants(List<Uri> participants) {
+        if (mConferenceHost == null) {
+            return;
+        }
+        mConferenceHost.performAddConferenceParticipants(participants);
+    }
+
+    /**
+     * Invoked when the conference is answered.
+     */
+    @Override
+    public void onAnswer(int videoState) {
+        if (mConferenceHost == null) {
+            return;
+        }
+        mConferenceHost.performAnswer(videoState);
+    }
+
+    /**
+     * Invoked when the conference is rejected.
+     */
+    @Override
+    public void onReject() {
+        if (mConferenceHost == null) {
+            return;
+        }
+        mConferenceHost.performReject(android.telecom.Call.REJECT_REASON_DECLINED);
+    }
+
+    /**
      * Invoked when the conference should be put on hold.
      */
     @Override
@@ -678,7 +758,8 @@
             setAddress(mConferenceHost.getAddress(), mConferenceHost.getAddressPresentation());
             setCallerDisplayName(mConferenceHost.getCallerDisplayName(),
                     mConferenceHost.getCallerDisplayNamePresentation());
-            setConnectionStartElapsedRealTime(mConferenceHost.getConnectElapsedTimeMillis());
+            setConnectionStartElapsedRealtimeMillis(
+                    mConferenceHost.getConnectionStartElapsedRealtimeMillis());
             setConnectionTime(mConferenceHost.getConnectTimeMillis());
         }
 
@@ -838,7 +919,8 @@
                             + "newParticipantcount=%d", oldParticipantCount, newParticipantCount);
             // If the single party call emulation fature flag is enabled, we can potentially treat
             // the conference as a single party call when there is just one participant.
-            if (mFeatureFlagProxy.isUsingSinglePartyCallEmulation()) {
+            if (mFeatureFlagProxy.isUsingSinglePartyCallEmulation() &&
+                    !mConferenceHost.isAdhocConferenceCall()) {
                 if (oldParticipantCount != 1 && newParticipantCount == 1) {
                     // If number of participants goes to 1, emulate a single party call.
                     startEmulatingSinglePartyCall();
@@ -895,7 +977,8 @@
             Log.d(this,
                     "stopEmulatingSinglePartyCall: restored lone participant connect time");
             loneParticipant.setConnectTimeMillis(getConnectionTime());
-            loneParticipant.setConnectionStartElapsedRealTime(getConnectionStartElapsedRealTime());
+            loneParticipant.setConnectionStartElapsedRealtimeMillis(
+                    getConnectionStartElapsedRealtimeMillis());
         }
 
         // Tell Telecom its a conference again.
@@ -935,7 +1018,8 @@
             setAddress(entry.getAddress(), entry.getAddressPresentation());
             setCallerDisplayName(entry.getCallerDisplayName(),
                     entry.getCallerDisplayNamePresentation());
-            setConnectionStartElapsedRealTime(entry.getConnectElapsedTimeMillis());
+            setConnectionStartElapsedRealtimeMillis(
+                    entry.getConnectionStartElapsedRealtimeMillis());
             setConnectionTime(entry.getConnectTimeMillis());
             mLoneParticipantIdentity = new Pair<>(entry.getUserEntity(), entry.getEndpoint());
 
@@ -979,10 +1063,11 @@
                 !isConferenceHost() /* isRemotelyHosted */);
         if (participant.getConnectTime() == 0) {
             connection.setConnectTimeMillis(parent.getConnectTimeMillis());
-            connection.setConnectionStartElapsedRealTime(parent.getConnectElapsedTimeMillis());
+            connection.setConnectionStartElapsedRealtimeMillis(
+                    parent.getConnectionStartElapsedRealtimeMillis());
         } else {
             connection.setConnectTimeMillis(participant.getConnectTime());
-            connection.setConnectionStartElapsedRealTime(participant.getConnectElapsedTime());
+            connection.setConnectionStartElapsedRealtimeMillis(participant.getConnectElapsedTime());
         }
         // Indicate whether this is an MT or MO call to Telecom; the participant has the cached
         // data from the time of merge.
@@ -1148,7 +1233,8 @@
                 c.updateState();
                 // Copy the connect time from the conferenceHost
                 c.setConnectTimeMillis(mConferenceHost.getConnectTimeMillis());
-                c.setConnectionStartElapsedRealTime(mConferenceHost.getConnectElapsedTimeMillis());
+                c.setConnectionStartElapsedRealtimeMillis(
+                        mConferenceHost.getConnectionStartElapsedRealtimeMillis());
                 mTelephonyConnectionService.addExistingConnection(phoneAccountHandle, c);
                 mTelephonyConnectionService.addConnectionToConferenceController(c);
             } // CDMA case not applicable for SRVCC
@@ -1173,11 +1259,13 @@
         switch (state) {
             case Connection.STATE_INITIALIZING:
             case Connection.STATE_NEW:
-            case Connection.STATE_RINGING:
                 // No-op -- not applicable.
                 break;
+            case Connection.STATE_RINGING:
+                setConferenceOnRinging();
+                break;
             case Connection.STATE_DIALING:
-                setDialing();
+                setConferenceOnDialing();
                 break;
             case Connection.STATE_DISCONNECTED:
                 DisconnectCause disconnectCause;
@@ -1198,10 +1286,10 @@
                 destroyTelephonyConference();
                 break;
             case Connection.STATE_ACTIVE:
-                setActive();
+                setConferenceOnActive();
                 break;
             case Connection.STATE_HOLDING:
-                setOnHold();
+                setConferenceOnHold();
                 break;
         }
     }
diff --git a/src/com/android/services/telephony/ImsConferenceController.java b/src/com/android/services/telephony/ImsConferenceController.java
index 1e10055..8789ba8 100644
--- a/src/com/android/services/telephony/ImsConferenceController.java
+++ b/src/com/android/services/telephony/ImsConferenceController.java
@@ -22,7 +22,7 @@
 import android.telecom.ConnectionService;
 import android.telecom.DisconnectCause;
 import android.telecom.PhoneAccountHandle;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
 
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
@@ -52,8 +52,19 @@
                 Log.v(ImsConferenceController.class, "onDestroyed: %s", conference);
             }
 
+            if (conference instanceof ImsConference) {
+                // Ims Conference call ended, so UE may now have the ability to initiate
+                // an Adhoc Conference call. Hence, try enabling adhoc conference capability
+                mTelecomAccountRegistry.refreshAdhocConference(true);
+            }
             mImsConferences.remove(conference);
         }
+
+        @Override
+        public void onStateChanged(Conference conference, int oldState, int newState) {
+            Log.v(this, "onStateChanged: Conference = " + conference);
+            recalculateConferenceable();
+        }
     };
 
     private final TelephonyConnection.TelephonyConnectionListener mTelephonyConnectionListener =
@@ -101,10 +112,11 @@
     private final ArrayList<TelephonyConnection> mTelephonyConnections = new ArrayList<>();
 
     /**
-     * List of known {@link ImsConference}s.  Realistically there will only ever be a single
-     * concurrent IMS conference.
+     * List of known {@link ImsConference}s. There can be upto maximum two Ims conference calls.
+     * One conference call can be a host conference call and another conference call formed as a
+     * result of accepting incoming conference call.
      */
-    private final ArrayList<ImsConference> mImsConferences = new ArrayList<>(1);
+    private final ArrayList<ImsConference> mImsConferences = new ArrayList<>(2);
 
     private TelecomAccountRegistry mTelecomAccountRegistry;
 
@@ -122,6 +134,17 @@
         mFeatureFlagProxy = featureFlagProxy;
     }
 
+    void addConference(ImsConference conference) {
+        if (mImsConferences.contains(conference)) {
+            // Adding a duplicate realistically shouldn't happen.
+            Log.w(this, "addConference - conference already tracked; conference=%s", conference);
+            return;
+        }
+        mImsConferences.add(conference);
+        conference.addTelephonyConferenceListener(mConferenceListener);
+        recalculateConferenceable();
+    }
+
     /**
      * Adds a new connection to the IMS conference controller.
      *
@@ -250,6 +273,11 @@
                 continue;
             }
 
+            // Since UE cannot host two conference calls, remove the ability to initiate
+            // another conference call as there already exists a conference call, which
+            // is hosted on this device.
+            mTelecomAccountRegistry.refreshAdhocConference(false);
+
             switch (conference.getState()) {
                 case Connection.STATE_ACTIVE:
                     //fall through
@@ -360,6 +388,10 @@
             Log.v(this, "Start new ImsConference - connection: %s", connection);
         }
 
+        if (connection.isAdhocConferenceCall()) {
+            Log.w(this, "start new ImsConference - control should never come here");
+            return;
+        }
         // Make a clone of the connection which will become the Ims conference host connection.
         // This is necessary since the Connection Service does not support removing a connection
         // from Telecom.  Instead we create a new instance and remove the old one from telecom.
diff --git a/src/com/android/services/telephony/MmiCodeUtil.java b/src/com/android/services/telephony/MmiCodeUtil.java
new file mode 100644
index 0000000..d208ec3
--- /dev/null
+++ b/src/com/android/services/telephony/MmiCodeUtil.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2020 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 java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public final class MmiCodeUtil {
+    //***** Constants
+
+    // Supp Service codes from TS 22.030 Annex B
+
+    //Called line presentation
+    static final String SC_CLIP    = "30";
+    static final String SC_CLIR    = "31";
+
+    // Call Forwarding
+    static final String SC_CFU     = "21";
+    static final String SC_CFB     = "67";
+    static final String SC_CFNRy   = "61";
+    static final String SC_CFNR    = "62";
+
+    static final String SC_CF_All = "002";
+    static final String SC_CF_All_Conditional = "004";
+
+    // Call Waiting
+    static final String SC_WAIT     = "43";
+
+    // Call Barring
+    static final String SC_BAOC         = "33";
+    static final String SC_BAOIC        = "331";
+    static final String SC_BAOICxH      = "332";
+    static final String SC_BAIC         = "35";
+    static final String SC_BAICr        = "351";
+
+    static final String SC_BA_ALL       = "330";
+    static final String SC_BA_MO        = "333";
+    static final String SC_BA_MT        = "353";
+
+    // Supp Service Password registration
+    static final String SC_PWD          = "03";
+
+    // PIN/PIN2/PUK/PUK2
+    static final String SC_PIN          = "04";
+    static final String SC_PIN2         = "042";
+    static final String SC_PUK          = "05";
+    static final String SC_PUK2         = "052";
+
+    // See TS 22.030 6.5.2 "Structure of the MMI"
+
+    static Pattern sPatternSuppService = Pattern.compile(
+        "((\\*|#|\\*#|\\*\\*|##)(\\d{2,3})(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#)(.*)");
+/*       1  2                    3          4  5       6   7         8    9     10  11             12
+
+         1 = Full string up to and including #
+         2 = action (activation/interrogation/registration/erasure)
+         3 = service code
+         5 = SIA
+         7 = SIB
+         9 = SIC
+         10 = dialing number
+*/
+
+    static final int MATCH_GROUP_SERVICE_CODE = 3;
+
+    public static final String BUTTON_CLIR_KEY  = "button_clir_key";
+    public static final String BUTTON_CW_KEY    = "button_cw_key";
+    public static final String CALL_FORWARDING_KEY = "call_forwarding_key";
+    public static final String CALL_BARRING_KEY = "call_barring_key";
+
+    //***** Public Class methods
+    public static String getMmiServiceCode(String dialString) {
+        Matcher m;
+        String ret = null;
+
+        m = sPatternSuppService.matcher(dialString);
+
+        if (m.matches()) {
+            ret = makeEmptyNull(m.group(MATCH_GROUP_SERVICE_CODE));
+        }
+
+        return ret;
+    }
+
+    private static String makeEmptyNull(String s) {
+        if (s != null && s.length() == 0) return null;
+
+        return s;
+    }
+
+    static boolean isServiceCodeCallForwarding(String sc) {
+        return sc != null &&
+                (sc.equals(SC_CFU)
+                || sc.equals(SC_CFB) || sc.equals(SC_CFNRy)
+                || sc.equals(SC_CFNR) || sc.equals(SC_CF_All)
+                || sc.equals(SC_CF_All_Conditional));
+    }
+
+    static boolean isServiceCodeCallBarring(String sc) {
+        return sc != null &&
+            (sc.equals(SC_BAOC)
+             || sc.equals(SC_BAOIC) || sc.equals(SC_BAOICxH)
+             || sc.equals(SC_BAIC) || sc.equals(SC_BAICr)
+             || sc.equals(SC_BA_ALL) || sc.equals(SC_BA_MO)
+             || sc.equals(SC_BA_MT));
+    }
+
+    static boolean isPinPukCommand(String sc) {
+        return sc != null && (sc.equals(SC_PIN) || sc.equals(SC_PIN2)
+                              || sc.equals(SC_PUK) || sc.equals(SC_PUK2));
+     }
+
+    public static String getSuppServiceKey(String dialString) {
+        String sc = getMmiServiceCode(dialString);
+        if (sc != null && sc.equals(SC_CLIP)) {
+            return "";
+        } else if (sc != null && sc.equals(SC_CLIR)) {
+            return BUTTON_CLIR_KEY;
+        } else if (isServiceCodeCallForwarding(sc)) {
+            return CALL_FORWARDING_KEY;
+        } else if (isServiceCodeCallBarring(sc)) {
+            return CALL_BARRING_KEY;
+        } else if (sc != null && sc.equals(SC_PWD)) {
+            return "";
+        } else if (sc != null && sc.equals(SC_WAIT)) {
+            return BUTTON_CW_KEY;
+        } else if (isPinPukCommand(sc)) {
+            return "";
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/src/com/android/services/telephony/PstnIncomingCallNotifier.java b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
index 2dfeaed..d2dfab5 100644
--- a/src/com/android/services/telephony/PstnIncomingCallNotifier.java
+++ b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
@@ -25,7 +25,7 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
 import android.text.TextUtils;
 
 import com.android.internal.telephony.Call;
@@ -288,7 +288,11 @@
             }
         } else {
             TelecomManager tm = mPhone.getContext().getSystemService(TelecomManager.class);
-            tm.addNewIncomingCall(handle, extras);
+            if (connection.isMultiparty()) {
+                tm.addNewIncomingConference(handle, extras);
+            } else {
+                tm.addNewIncomingCall(handle, extras);
+            }
         }
     }
 
diff --git a/src/com/android/services/telephony/RadioOnHelper.java b/src/com/android/services/telephony/RadioOnHelper.java
index 981dc96..25ac220 100644
--- a/src/com/android/services/telephony/RadioOnHelper.java
+++ b/src/com/android/services/telephony/RadioOnHelper.java
@@ -77,7 +77,8 @@
      * RadioOnHelper's handler (thus ensuring that the rest of the sequence is entirely
      * serialized, and runs on the main looper.)
      */
-    public void triggerRadioOnAndListen(RadioOnStateListener.Callback callback) {
+    public void triggerRadioOnAndListen(RadioOnStateListener.Callback callback,
+            boolean forEmergencyCall, Phone phoneForEmergencyCall) {
         setupListeners();
         mCallback = callback;
         mInProgressListeners.clear();
@@ -89,16 +90,17 @@
             }
 
             mInProgressListeners.add(mListeners.get(i));
-            mListeners.get(i).waitForRadioOn(phone, this);
+            mListeners.get(i).waitForRadioOn(phone, this, forEmergencyCall,
+                    forEmergencyCall && phone == phoneForEmergencyCall);
         }
 
-        powerOnRadio();
+        powerOnRadio(forEmergencyCall, phoneForEmergencyCall);
     }
     /**
      * Attempt to power on the radio (i.e. take the device out of airplane mode). We'll eventually
      * get an onServiceStateChanged() callback when the radio successfully comes up.
      */
-    private void powerOnRadio() {
+    private void powerOnRadio(boolean forEmergencyCall, Phone phoneForEmergencyCall) {
 
         // If airplane mode is on, we turn it off the same way that the Settings activity turns it
         // off.
@@ -110,6 +112,11 @@
             Settings.Global.putInt(mContext.getContentResolver(),
                     Settings.Global.AIRPLANE_MODE_ON, 0);
 
+            for (Phone phone : PhoneFactory.getPhones()) {
+                Log.d(this, "powerOnRadio, enabling Radio");
+                phone.setRadioPower(true, forEmergencyCall, phone == phoneForEmergencyCall, false);
+            }
+
             // Post the broadcast intend for change in airplane mode
             // TODO: We really should not be in charge of sending this broadcast.
             // If changing the setting is sufficient to trigger all of the rest of the logic,
diff --git a/src/com/android/services/telephony/RadioOnStateListener.java b/src/com/android/services/telephony/RadioOnStateListener.java
index 52bd9cf..93e1e3c 100644
--- a/src/com/android/services/telephony/RadioOnStateListener.java
+++ b/src/com/android/services/telephony/RadioOnStateListener.java
@@ -56,6 +56,9 @@
     @VisibleForTesting
     public static final int MSG_SERVICE_STATE_CHANGED = 2;
     private static final int MSG_RETRY_TIMEOUT = 3;
+    @VisibleForTesting
+    public static final int MSG_RADIO_ON = 4;
+    public static final int MSG_RADIO_OFF_OR_NOT_AVAILABLE = 5;
 
     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
         @Override
@@ -67,7 +70,10 @@
                         Phone phone = (Phone) args.arg1;
                         RadioOnStateListener.Callback callback =
                                 (RadioOnStateListener.Callback) args.arg2;
-                        startSequenceInternal(phone, callback);
+                        boolean forEmergencyCall = (boolean) args.arg3;
+                        boolean isSelectedPhoneForEmergencyCall = (boolean) args.arg4;
+                        startSequenceInternal(phone, callback, forEmergencyCall,
+                                isSelectedPhoneForEmergencyCall);
                     } finally {
                         args.recycle();
                     }
@@ -75,6 +81,12 @@
                 case MSG_SERVICE_STATE_CHANGED:
                     onServiceStateChanged((ServiceState) ((AsyncResult) msg.obj).result);
                     break;
+                case MSG_RADIO_ON:
+                    onRadioOn();
+                    break;
+                case MSG_RADIO_OFF_OR_NOT_AVAILABLE:
+                    registerForRadioOn();
+                    break;
                 case MSG_RETRY_TIMEOUT:
                     onRetryTimeout();
                     break;
@@ -88,6 +100,10 @@
 
     private Callback mCallback;  // The callback to notify upon completion.
     private Phone mPhone;  // The phone that will attempt to place the call.
+    private boolean mForEmergencyCall; // Whether radio is being turned on for emergency call.
+    // Whether this phone is selected to place emergency call. Can be true only if
+    // mForEmergencyCall is true.
+    private boolean mSelectedPhoneForEmergencyCall;
     private int mNumRetriesSoFar;
 
     /**
@@ -104,7 +120,8 @@
      * RadioOnStateListener's handler (thus ensuring that the rest of the sequence is entirely
      * serialized, and runs only on the handler thread.)
      */
-    public void waitForRadioOn(Phone phone, Callback callback) {
+    public void waitForRadioOn(Phone phone, Callback callback,
+            boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall) {
         Log.d(this, "waitForRadioOn: Phone " + phone.getPhoneId());
 
         if (mPhone != null) {
@@ -115,6 +132,8 @@
         SomeArgs args = SomeArgs.obtain();
         args.arg1 = phone;
         args.arg2 = callback;
+        args.arg3 = forEmergencyCall;
+        args.arg4 = isSelectedPhoneForEmergencyCall;
         mHandler.obtainMessage(MSG_START_SEQUENCE, args).sendToTarget();
     }
 
@@ -123,7 +142,8 @@
      *
      * @see #waitForRadioOn
      */
-    private void startSequenceInternal(Phone phone, Callback callback) {
+    private void startSequenceInternal(Phone phone, Callback callback,
+            boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall) {
         Log.d(this, "startSequenceInternal: Phone " + phone.getPhoneId());
 
         // First of all, clean up any state left over from a prior RadioOn call sequence. This
@@ -133,8 +153,13 @@
 
         mPhone = phone;
         mCallback = callback;
+        mForEmergencyCall = forEmergencyCall;
+        mSelectedPhoneForEmergencyCall = isSelectedPhoneForEmergencyCall;
 
         registerForServiceStateChanged();
+        // Register for RADIO_OFF to handle cases where emergency call is dialed before
+        // we receive UNSOL_RESPONSE_RADIO_STATE_CHANGED with RADIO_OFF.
+        registerForRadioOff();
         // Next step: when the SERVICE_STATE_CHANGED event comes in, we'll retry the call; see
         // onServiceStateChanged(). But also, just in case, start a timer to make sure we'll retry
         // the call even if the SERVICE_STATE_CHANGED event never comes in for some reason.
@@ -147,6 +172,7 @@
      * call with {@link Callback#isOkToCall}
      */
     private void onServiceStateChanged(ServiceState state) {
+        if (mPhone == null) return;
         Log.d(this, "onServiceStateChanged(), new state = %s, Phone = %s", state,
                 mPhone.getPhoneId());
 
@@ -169,6 +195,18 @@
         }
     }
 
+    private void onRadioOn() {
+        if (mPhone == null) return;
+        ServiceState state =  mPhone.getServiceState();
+        Log.d(this, "onRadioOn, state = %s, Phone = %s", state,
+                mPhone.getPhoneId());
+        if (isOkToCall(state.getState())) {
+            onComplete(true);
+            cleanup();
+        } else {
+            Log.d(this, "onRadioOn: not ready to call yet, keep waiting.");
+        }
+    }
     /**
      * Callback to see if it is okay to call yet, given the current conditions.
      */
@@ -180,6 +218,7 @@
      * Handles the retry timer expiring.
      */
     private void onRetryTimeout() {
+        if (mPhone == null) return;
         int serviceState = mPhone.getServiceState().getState();
         Log.d(this, "onRetryTimeout():  phone state = %s, service state = %d, retries = %d.",
                 mPhone.getState(), serviceState, mNumRetriesSoFar);
@@ -208,7 +247,8 @@
                 cleanup();
             } else {
                 Log.d(this, "Trying (again) to turn on the radio.");
-                mPhone.setRadioPower(true);
+                mPhone.setRadioPower(true, mForEmergencyCall, mSelectedPhoneForEmergencyCall,
+                        false);
                 startRetryTimer();
             }
         }
@@ -239,6 +279,8 @@
         onComplete(false);
 
         unregisterForServiceStateChanged();
+        unregisterForRadioOff();
+        unregisterForRadioOn();
         cancelRetryTimer();
 
         // Used for unregisterForServiceStateChanged() so we null it out here instead.
@@ -271,6 +313,31 @@
         mHandler.removeMessages(MSG_SERVICE_STATE_CHANGED);  // Clean up any pending messages too
     }
 
+    private void registerForRadioOff() {
+        mPhone.mCi.registerForOffOrNotAvailable(mHandler, MSG_RADIO_OFF_OR_NOT_AVAILABLE, null);
+    }
+
+    private void unregisterForRadioOff() {
+        // This method is safe to call even if we haven't set mPhone yet.
+        if (mPhone != null) {
+            mPhone.mCi.unregisterForOffOrNotAvailable(mHandler);  // Safe even if unnecessary
+        }
+        mHandler.removeMessages(MSG_RADIO_OFF_OR_NOT_AVAILABLE);  // Clean up any pending messages
+    }
+
+    private void registerForRadioOn() {
+        unregisterForRadioOff();
+        mPhone.mCi.registerForOn(mHandler, MSG_RADIO_ON, null);
+    }
+
+    private void unregisterForRadioOn() {
+        // This method is safe to call even if we haven't set mPhone yet.
+        if (mPhone != null) {
+            mPhone.mCi.unregisterForOn(mHandler);  // Safe even if unnecessary
+        }
+        mHandler.removeMessages(MSG_RADIO_ON);  // Clean up any pending messages too
+    }
+
     private void onComplete(boolean isRadioReady) {
         if (mCallback != null) {
             Callback tempCallback = mCallback;
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 5a1e6a6..1013927 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -41,7 +41,6 @@
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneStateListener;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -49,6 +48,8 @@
 import android.telephony.TelephonyManager;
 import android.telephony.ims.ImsException;
 import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.RegistrationManager;
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.text.TextUtils;
@@ -60,6 +61,7 @@
 import com.android.phone.PhoneGlobals;
 import com.android.phone.PhoneUtils;
 import com.android.phone.R;
+import com.android.telephony.Rlog;
 
 import java.util.Arrays;
 import java.util.LinkedList;
@@ -86,9 +88,11 @@
         private final PstnPhoneCapabilitiesNotifier mPhoneCapabilitiesNotifier;
         private boolean mIsEmergency;
         private boolean mIsRttCapable;
+        private boolean mIsAdhocConfCapable;
         private boolean mIsEmergencyPreferred;
         private MmTelFeature.MmTelCapabilities mMmTelCapabilities;
         private ImsMmTelManager.CapabilityCallback mMmtelCapabilityCallback;
+        private RegistrationManager.RegistrationCallback mImsRegistrationCallback;
         private ImsMmTelManager mMmTelManager;
         private final boolean mIsDummy;
         private boolean mIsVideoCapable;
@@ -106,6 +110,7 @@
             mPhone = phone;
             mIsEmergency = isEmergency;
             mIsDummy = isDummy;
+            mIsAdhocConfCapable = mPhone.isImsRegistered();
             mAccount = registerPstnPhoneAccount(isEmergency, isDummy);
             Log.i(this, "Registered phoneAccount: %s with handle: %s",
                     mAccount, mAccount.getAccountHandle());
@@ -138,15 +143,38 @@
                     updateRttCapability();
                 }
             };
-
             registerMmTelCapabilityCallback();
+
+            mImsRegistrationCallback = new RegistrationManager.RegistrationCallback() {
+                @Override
+                public void onRegistered(int imsRadioTech) {
+                    updateAdhocConfCapability(true);
+                }
+
+                @Override
+                public void onRegistering(int imsRadioTech) {
+                    updateAdhocConfCapability(false);
+                }
+
+                @Override
+                public void onUnregistered(ImsReasonInfo imsReasonInfo) {
+                    updateAdhocConfCapability(false);
+                }
+            };
+            registerImsRegistrationCallback();
         }
 
         void teardown() {
             mIncomingCallNotifier.teardown();
             mPhoneCapabilitiesNotifier.teardown();
-            if (mMmTelManager != null && mMmtelCapabilityCallback != null) {
-                mMmTelManager.unregisterMmTelCapabilityCallback(mMmtelCapabilityCallback);
+            if (mMmTelManager != null) {
+                if (mMmtelCapabilityCallback != null) {
+                    mMmTelManager.unregisterMmTelCapabilityCallback(mMmtelCapabilityCallback);
+                }
+
+                if (mImsRegistrationCallback != null) {
+                    mMmTelManager.unregisterImsRegistrationCallback(mImsRegistrationCallback);
+                }
             }
         }
 
@@ -171,6 +199,25 @@
             }
         }
 
+        private void registerImsRegistrationCallback() {
+            if (mMmTelManager == null || mImsRegistrationCallback == null) {
+                return;
+            }
+
+            try {
+                mMmTelManager.registerImsRegistrationCallback(mContext.getMainExecutor(),
+                        mImsRegistrationCallback);
+            } catch (ImsException e) {
+                Log.w(this, "registerImsRegistrationCallback: registration failed, no ImsService"
+                        + " available. Exception: " + e.getMessage());
+                return;
+            } catch (IllegalArgumentException e) {
+                Log.w(this, "registerImsRegistrationCallback: registration failed, invalid"
+                        + " subscription, Exception" + e.getMessage());
+                return;
+            }
+        }
+
         /**
          * Trigger re-registration of this account.
          */
@@ -226,6 +273,7 @@
             // slotId from the subId or the phoneId in all instances.
             SubscriptionInfo record =
                     mSubscriptionManager.getActiveSubscriptionInfo(subId);
+            TelephonyManager tm = mTelephonyManager.createForSubscriptionId(subId);
 
             if (isEmergency) {
                 label = mContext.getResources().getString(R.string.sim_label_emergency_calls);
@@ -234,7 +282,7 @@
             } else if (mTelephonyManager.getPhoneCount() == 1) {
                 // For single-SIM devices, we show the label and description as whatever the name of
                 // the network is.
-                description = label = mTelephonyManager.getNetworkOperatorName();
+                description = label = tm.getNetworkOperatorName();
             } else {
                 CharSequence subDisplayName = null;
 
@@ -321,6 +369,12 @@
                 extras.putAll(getPhoneAccountExtras());
             }
 
+            if (mIsAdhocConfCapable && isCarrierAdhocConferenceCallSupported()) {
+                capabilities |= PhoneAccount.CAPABILITY_ADHOC_CONFERENCE_CALLING;
+            } else {
+                capabilities &= ~PhoneAccount.CAPABILITY_ADHOC_CONFERENCE_CALLING;
+            }
+
             final boolean isHandoverFromSupported = mContext.getResources().getBoolean(
                     R.bool.config_support_handover_from);
             if (isHandoverFromSupported && !isEmergency) {
@@ -511,6 +565,19 @@
         }
 
         /**
+         * Determines from carrier config whether adhoc conference calling is supported.
+         *
+         * @return {@code true} if adhoc conference calling is supported, {@code false} otherwise.
+         */
+        private boolean isCarrierAdhocConferenceCallSupported() {
+            PersistableBundle b =
+                    PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
+            return b != null &&
+                    b.getBoolean(CarrierConfigManager.KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL);
+        }
+
+
+        /**
          * Determines from carrier config whether merging calls is supported.
          *
          * @return {@code true} if merging calls is supported, {@code false} otherwise.
@@ -664,6 +731,26 @@
             }
         }
 
+        public void updateAdhocConfCapability(boolean isAdhocConfCapable) {
+            synchronized (mAccountsLock) {
+                if (!mAccounts.contains(this)) {
+                    // Account has already been torn down, don't try to register it again.
+                    // This handles the case where teardown has already happened, and we got a Ims
+                    // registartion update that lost the race for the mAccountsLock.  In such a
+                    // scenario by the time we get here, the original phone account could have been
+                    // torn down.
+                    return;
+                }
+
+                if (isAdhocConfCapable !=  mIsAdhocConfCapable) {
+                    Log.i(this, "updateAdhocConfCapability - changed, new value: "
+                            + isAdhocConfCapable);
+                    mIsAdhocConfCapable = isAdhocConfCapable;
+                    mAccount = registerPstnPhoneAccount(mIsEmergency, mIsDummy);
+                }
+            }
+        }
+
         public void updateRttCapability() {
             boolean isRttEnabled = isRttCurrentlySupported();
             if (isRttEnabled != mIsRttCapable) {
@@ -1048,6 +1135,21 @@
         return null;
     }
 
+    public void refreshAdhocConference(boolean isEnableAdhocConf) {
+        synchronized (mAccountsLock) {
+            Log.v(this, "refreshAdhocConference isEnable = " + isEnableAdhocConf);
+            for (AccountEntry entry : mAccounts) {
+                boolean hasAdhocConfCapability = entry.mAccount.hasCapabilities(
+                        PhoneAccount.CAPABILITY_ADHOC_CONFERENCE_CALLING);
+                if (!isEnableAdhocConf && hasAdhocConfCapability) {
+                    entry.updateAdhocConfCapability(isEnableAdhocConf);
+                } else if (isEnableAdhocConf && !hasAdhocConfCapability) {
+                    entry.updateAdhocConfCapability(entry.mPhone.isImsRegistered());
+                }
+            }
+        }
+    }
+
     /**
      * Returns whethere a the subscription associated with a {@link PhoneAccountHandle} is using a
      * sim call manager.
@@ -1214,30 +1316,6 @@
 
         // Clean up any PhoneAccounts that are no longer relevant
         cleanupPhoneAccounts();
-
-        // At some point, the phone account ID was switched from the subId to the iccId.
-        // If there is a default account, check if this is the case, and upgrade the default account
-        // from using the subId to iccId if so.
-        PhoneAccountHandle defaultPhoneAccount =
-                mTelecomManager.getUserSelectedOutgoingPhoneAccount();
-        ComponentName telephonyComponentName =
-                new ComponentName(mContext, TelephonyConnectionService.class);
-
-        if (defaultPhoneAccount != null &&
-                telephonyComponentName.equals(defaultPhoneAccount.getComponentName()) &&
-                !hasAccountEntryForPhoneAccount(defaultPhoneAccount)) {
-
-            String phoneAccountId = defaultPhoneAccount.getId();
-            if (!TextUtils.isEmpty(phoneAccountId) && TextUtils.isDigitsOnly(phoneAccountId)) {
-                PhoneAccountHandle upgradedPhoneAccount =
-                        PhoneUtils.makePstnPhoneAccountHandle(
-                                PhoneGlobals.getPhone(Integer.parseInt(phoneAccountId)));
-
-                if (hasAccountEntryForPhoneAccount(upgradedPhoneAccount)) {
-                    mTelecomManager.setUserSelectedOutgoingPhoneAccount(upgradedPhoneAccount);
-                }
-            }
-        }
     }
 
     private void tearDownAccounts() {
diff --git a/src/com/android/services/telephony/TelephonyConference.java b/src/com/android/services/telephony/TelephonyConference.java
index afbe89d..7e4693f 100644
--- a/src/com/android/services/telephony/TelephonyConference.java
+++ b/src/com/android/services/telephony/TelephonyConference.java
@@ -16,6 +16,7 @@
 
 package com.android.services.telephony;
 
+import android.net.Uri;
 import android.telecom.Connection;
 import android.telecom.PhoneAccountHandle;
 
@@ -93,6 +94,22 @@
     }
 
     @Override
+    public void onAnswer(int videoState) {
+        Log.e(this, new Exception(), "Answer not supported for GSM conference call.");
+    }
+
+    @Override
+    public void onReject() {
+        Log.e(this, new Exception(), "Reject not supported for GSM conference call.");
+    }
+
+    @Override
+    public void onAddConferenceParticipants(List<Uri> participants) {
+        Log.e(this, new Exception(), "Adding Conference Participants not supported " +
+                " for GSM conference call.");
+    }
+
+    @Override
     public void onMerge(Connection connection) {
         try {
             Phone phone = ((TelephonyConnection) connection).getPhone();
diff --git a/src/com/android/services/telephony/TelephonyConferenceBase.java b/src/com/android/services/telephony/TelephonyConferenceBase.java
index 5e7ecf6..1c81fb9 100644
--- a/src/com/android/services/telephony/TelephonyConferenceBase.java
+++ b/src/com/android/services/telephony/TelephonyConferenceBase.java
@@ -48,6 +48,14 @@
         public void onConferenceMembershipChanged(Connection connection) {}
 
         /**
+         * Listener called when there conference call state changes.
+         * @param conference The conference.
+         * @param oldState previous state of conference call.
+         * @param newState new state of conference call.
+         */
+        public void onStateChanged(Conference conference, int oldState, int newState) {}
+
+        /**
          * Listener called when a conference is destroyed.
          * @param conference The conference.
          */
@@ -129,6 +137,54 @@
     }
 
     /**
+     * Sets state to be on hold.
+     */
+     public final void setConferenceOnHold() {
+         int oldState = getState();
+         if (oldState == Connection.STATE_HOLDING) {
+             return;
+         }
+         setOnHold();
+         notifyStateChanged(oldState, getState());
+     }
+
+     /**
+      * Sets state to be dialing.
+      */
+     public final void setConferenceOnDialing() {
+         int oldState = getState();
+         if (oldState == Connection.STATE_DIALING) {
+             return;
+         }
+         setDialing();
+         notifyStateChanged(oldState, getState());
+     }
+
+     /**
+      * Sets state to be ringing.
+      */
+     public final void setConferenceOnRinging() {
+         int oldState = getState();
+         if (oldState == Connection.STATE_RINGING) {
+             return;
+         }
+         setRinging();
+         notifyStateChanged(oldState, getState());
+     }
+
+     /**
+      * Sets state to be active.
+      */
+     public final void setConferenceOnActive() {
+         int oldState = getState();
+         if (oldState == Connection.STATE_ACTIVE) {
+             return;
+         }
+         setActive();
+         notifyStateChanged(oldState, getState());
+     }
+
+    /**
      * Updates RIL voice radio technology used for current conference after its creation.
      */
     public void updateCallRadioTechAfterCreation() {
@@ -188,4 +244,12 @@
             listener.onDestroyed(this);
         }
     }
+
+    private void notifyStateChanged(int oldState, int newState) {
+        if (oldState != newState) {
+            for (TelephonyConferenceListener listener : mListeners) {
+                listener.onStateChanged(this, oldState, newState);
+            }
+        }
+    }
 }
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
old mode 100644
new mode 100755
index fb865b4..004a699
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -37,12 +37,11 @@
 import android.telecom.StatusHints;
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
-import android.telephony.Annotation.RilRadioTechnology;
 import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
+import android.telephony.ServiceState.RilRadioTechnology;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.ims.ImsCallProfile;
@@ -51,6 +50,7 @@
 import android.util.Pair;
 
 import com.android.ims.ImsCall;
+import com.android.ims.ImsException;
 import com.android.ims.internal.ConferenceParticipant;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.SomeArgs;
@@ -63,12 +63,14 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
 import com.android.internal.telephony.imsphone.ImsPhone;
+import com.android.internal.telephony.imsphone.ImsPhoneCall;
 import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
 import com.android.internal.telephony.imsphone.ImsPhoneConnection;
 import com.android.phone.ImsUtil;
 import com.android.phone.PhoneGlobals;
 import com.android.phone.PhoneUtils;
 import com.android.phone.R;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -113,6 +115,13 @@
     private static final int MSG_SET_CALL_RADIO_TECH = 18;
     private static final int MSG_ON_CONNECTION_EVENT = 19;
     private static final int MSG_REDIAL_CONNECTION_CHANGED = 20;
+    private static final int MSG_REJECT = 21;
+
+    private static final String JAPAN_COUNTRY_CODE_WITH_PLUS_SIGN = "+81";
+    private static final String JAPAN_ISO_COUNTRY_CODE = "JP";
+
+    private List<Uri> mParticipants;
+    private boolean mIsAdhocConferenceCall;
 
     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
         @Override
@@ -163,7 +172,9 @@
                                 "not foreground connection, skipping");
                         return;
                     }
-                    setRingbackRequested((Boolean) ((AsyncResult) msg.obj).result);
+                    boolean ringback = (Boolean) ((AsyncResult) msg.obj).result;
+                    setRingbackRequested(ringback);
+                    notifyRingbackRequested(ringback);
                     break;
                 case MSG_DISCONNECT:
                     updateState();
@@ -268,6 +279,10 @@
                     int cause = (int) msg.obj;
                     hangup(cause);
                     break;
+                case MSG_REJECT:
+                    int rejectReason = (int) msg.obj;
+                    reject(rejectReason);
+                    break;
 
                 case MSG_SET_CALL_RADIO_TECH:
                     int vrat = (int) msg.obj;
@@ -463,6 +478,7 @@
         public void onVideoProviderChanged(android.telecom.Connection c,
                 Connection.VideoProvider videoProvider) {}
         public void onVideoStateChanged(android.telecom.Connection c, int videoState) {}
+        public void onRingbackRequested(Connection c, boolean ringback) {}
     }
 
     private final PostDialListener mPostDialListener = new PostDialListener() {
@@ -859,6 +875,11 @@
     }
 
     @Override
+    public void onAddConferenceParticipants(List<Uri> participants) {
+        performAddConferenceParticipants(participants);
+    }
+
+    @Override
     public void onAbort() {
         Log.v(this, "onAbort");
         mHandler.obtainMessage(MSG_HANGUP, android.telephony.DisconnectCause.LOCAL).sendToTarget();
@@ -876,14 +897,7 @@
 
     @Override
     public void onAnswer(int videoState) {
-        Log.v(this, "onAnswer");
-        if (isValidRingingCall() && getPhone() != null) {
-            try {
-                getPhone().acceptCall(videoState);
-            } catch (CallStateException e) {
-                Log.e(this, e, "Failed to accept call.");
-            }
-        }
+        performAnswer(videoState);
     }
 
     @Override
@@ -927,15 +941,76 @@
 
     @Override
     public void onReject() {
-        Log.v(this, "onReject");
+        performReject(android.telecom.Call.REJECT_REASON_DECLINED);
+    }
+
+    @Override
+    public void onReject(@android.telecom.Call.RejectReason int rejectReason) {
+        performReject(rejectReason);
+    }
+
+    public void performReject(int rejectReason) {
+        Log.v(this, "performReject");
         if (isValidRingingCall()) {
-            mHandler.obtainMessage(MSG_HANGUP, android.telephony.DisconnectCause.INCOMING_REJECTED)
+            mHandler.obtainMessage(MSG_REJECT, rejectReason)
                     .sendToTarget();
         }
         super.onReject();
     }
 
     @Override
+    public void onTransfer(Uri number, boolean isConfirmationRequired) {
+        Log.v(this, "onTransfer");
+        if (mOriginalConnection != null) {
+            if (number == null) {
+                Log.w(this, "call transfer uri is null");
+                return;
+            }
+            String scheme = number.getScheme();
+            String transferNumber = "";
+            String uriString = number.getSchemeSpecificPart();
+            if (!PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
+                if (!PhoneAccount.SCHEME_TEL.equals(scheme)) {
+                    Log.w(this, "onTransfer, number scheme is not of type tel instead: "
+                            + scheme);
+                    return;
+                }
+                if (PhoneNumberUtils.isUriNumber(uriString)) {
+                    Log.w(this, "Invalid transfer address. Not a legal PSTN number.");
+                    return;
+                }
+                transferNumber = PhoneNumberUtils.convertAndStrip(uriString);
+                if (TextUtils.isEmpty(transferNumber)) {
+                    Log.w(this, "Empty transfer number obtained from uri");
+                    return;
+                }
+            } else {
+                Log.w(this, "Cannot transfer to voicemail uri");
+                return;
+            }
+
+            try {
+                mOriginalConnection.transfer(transferNumber, isConfirmationRequired);
+            } catch (CallStateException e) {
+                Log.e(this, e, "Failed to transfer call.");
+            }
+        }
+    }
+
+    @Override
+    public void onTransfer(Connection otherConnection) {
+        Log.v(this, "onConsultativeTransfer");
+        if (mOriginalConnection != null && (otherConnection instanceof TelephonyConnection)) {
+            try {
+                mOriginalConnection.consultativeTransfer(
+                        ((TelephonyConnection) otherConnection).getOriginalConnection());
+            } catch (CallStateException e) {
+                Log.e(this, e, "Failed to transfer call.");
+            }
+        }
+    }
+
+    @Override
     public void onPostDialContinue(boolean proceed) {
         Log.v(this, "onPostDialContinue, proceed: " + proceed);
         if (mOriginalConnection != null) {
@@ -1001,6 +1076,17 @@
         originalConnection.sendRttModifyResponse(textStream);
     }
 
+    public void performAnswer(int videoState) {
+        Log.v(this, "performAnswer");
+        if (isValidRingingCall() && getPhone() != null) {
+            try {
+                getPhone().acceptCall(videoState);
+            } catch (CallStateException e) {
+                Log.e(this, e, "Failed to accept call.");
+            }
+        }
+    }
+
     public void performHold() {
         Log.v(this, "performHold");
         // TODO: Can dialing calls be put on hold as well since they take up the
@@ -1096,6 +1182,29 @@
         }
     }
 
+    private String[] getAddConferenceParticipants(List<Uri> participants) {
+        String[] addConfParticipants = new String[participants.size()];
+        int i = 0;
+        for (Uri participant : participants) {
+           addConfParticipants[i] = participant.getSchemeSpecificPart();
+           i++;
+        }
+        return addConfParticipants;
+    }
+
+    public void performAddConferenceParticipants(List<Uri> participants) {
+        Log.v(this, "performAddConferenceParticipants");
+        if (mOriginalConnection.getCall() instanceof ImsPhoneCall) {
+            ImsPhoneCall imsPhoneCall = (ImsPhoneCall)mOriginalConnection.getCall();
+            try {
+                imsPhoneCall.getImsCall().inviteParticipants(
+                        getAddConferenceParticipants(participants));
+            } catch(ImsException e) {
+                Log.e(this, e, "failed to add conference participants");
+            }
+        }
+    }
+
     /**
      * Builds connection capabilities common to all TelephonyConnections. Namely, apply IMS-based
      * capabilities.
@@ -1130,6 +1239,12 @@
         newCapabilities = changeBitmask(newCapabilities, CAPABILITY_SUPPORT_DEFLECT,
                 isImsConnection() && canDeflectImsCalls());
 
+        newCapabilities = applyAddParticipantCapabilities(newCapabilities);
+        newCapabilities = changeBitmask(newCapabilities, CAPABILITY_TRANSFER_CONSULTATIVE,
+                isImsConnection() && canConsultativeTransfer());
+        newCapabilities = changeBitmask(newCapabilities, CAPABILITY_TRANSFER,
+                isImsConnection() && canTransferToNumber());
+
         if (getConnectionCapabilities() != newCapabilities) {
             setConnectionCapabilities(newCapabilities);
             notifyConnectionCapabilitiesChanged(newCapabilities);
@@ -1162,11 +1277,13 @@
                 isExternalConnection());
         newProperties = changeBitmask(newProperties, PROPERTY_HAS_CDMA_VOICE_PRIVACY,
                 mIsCdmaVoicePrivacyEnabled);
-        newProperties = changeBitmask(newProperties, PROPERTY_ASSISTED_DIALING_USED,
+        newProperties = changeBitmask(newProperties, PROPERTY_ASSISTED_DIALING,
                 mIsUsingAssistedDialing);
         newProperties = changeBitmask(newProperties, PROPERTY_IS_RTT, isRtt());
         newProperties = changeBitmask(newProperties, PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL,
                 isNetworkIdentifiedEmergencyCall());
+        newProperties = changeBitmask(newProperties, PROPERTY_IS_ADHOC_CONFERENCE,
+                isAdhocConferenceCall());
 
         if (getConnectionProperties() != newProperties) {
             setTelephonyConnectionProperties(newProperties);
@@ -1186,6 +1303,9 @@
             if (isShowingOriginalDialString()
                     && mOriginalConnection.getOrigDialString() != null) {
                 address = getAddressFromNumber(mOriginalConnection.getOrigDialString());
+            } else if (isNeededToFormatIncomingNumberForJp()) {
+                address = getAddressFromNumber(
+                        formatIncomingNumberForJp(mOriginalConnection.getAddress()));
             } else {
                 address = getAddressFromNumber(mOriginalConnection.getAddress());
             }
@@ -1255,6 +1375,7 @@
         setTelephonyVideoState(mOriginalConnection.getVideoState());
         setOriginalConnectionCapabilities(mOriginalConnection.getConnectionCapabilities());
         setIsNetworkIdentifiedEmergencyCall(mOriginalConnection.isNetworkIdentifiedEmergencyCall());
+        setIsAdhocConferenceCall(mOriginalConnection.isAdhocConference());
         setAudioModeIsVoip(mOriginalConnection.getAudioModeIsVoip());
         setTelephonyVideoProvider(mOriginalConnection.getVideoProvider());
         setAudioQuality(mOriginalConnection.getAudioQuality());
@@ -1511,6 +1632,39 @@
         return true;
     }
 
+    /**
+     * @return The address's to which this Connection is currently communicating.
+     */
+    public final @Nullable List<Uri> getParticipants() {
+        return mParticipants;
+    }
+
+    /**
+     * Sets the value of the {@link #getParticipants()} property.
+     *
+     * @param address The participant address's.
+     */
+    public final void setParticipants(@Nullable List<Uri> address) {
+        mParticipants = address;
+    }
+
+    /**
+     * @return true if connection is adhocConference call else false.
+     */
+    public final boolean isAdhocConferenceCall() {
+        return mIsAdhocConferenceCall;
+    }
+
+    /**
+     * Sets the value of the {@link #isAdhocConferenceCall()} property.
+     *
+     * @param isAdhocConferenceCall represents if the call is adhoc conference call or not.
+     */
+    public void setIsAdhocConferenceCall(boolean isAdhocConferenceCall) {
+        mIsAdhocConferenceCall = isAdhocConferenceCall;
+        updateConnectionProperties();
+    }
+
     private boolean canHoldImsCalls() {
         PersistableBundle b = getCarrierConfig();
         // Return true if the CarrierConfig is unavailable
@@ -1520,6 +1674,75 @@
                 || !VideoProfile.isVideo(getVideoState()));
     }
 
+    private boolean isConferenceHosted() {
+        boolean isHosted = false;
+        if (getTelephonyConnectionService() != null) {
+            for (Conference current : getTelephonyConnectionService().getAllConferences()) {
+                if (current instanceof ImsConference) {
+                    ImsConference other = (ImsConference) current;
+                    if (getState() == current.getState()) {
+                        continue;
+                    }
+                    if (other.isConferenceHost()) {
+                        isHosted = true;
+                        break;
+                    }
+                }
+            }
+        }
+        return isHosted;
+    }
+
+    private boolean isAddParticipantCapable() {
+        // not add participant capable for non ims phones
+        if (getPhone() == null || getPhone().getPhoneType() != PhoneConstants.PHONE_TYPE_IMS) {
+            return false;
+        }
+
+        if (!getCarrierConfig()
+                .getBoolean(CarrierConfigManager.KEY_SUPPORT_ADD_CONFERENCE_PARTICIPANTS_BOOL)) {
+            return false;
+        }
+
+        boolean isCapable = !mTreatAsEmergencyCall && (mConnectionState == Call.State.ACTIVE ||
+                mConnectionState == Call.State.HOLDING);
+
+        // add participant capable if current connection is a host connection or
+        // if conference is not hosted on the device
+        isCapable = isCapable && ((mOriginalConnection != null &&
+                mOriginalConnection.isConferenceHost()) ||
+                !isConferenceHosted());
+
+        /**
+          * For individual IMS calls, if the extra for remote conference support is
+          *     - indicated, then consider the same for add participant capability
+          *     - not indicated, then the add participant capability is same as before.
+          */
+        if (isCapable && (mOriginalConnection != null) && !mIsMultiParty) {
+            isCapable = mOriginalConnectionExtras.getBoolean(
+                    ImsCallProfile.EXTRA_CONFERENCE_AVAIL, isCapable);
+        }
+        return isCapable;
+    }
+
+    /**
+     * Applies the add participant capabilities to the {@code CallCapabilities} bit-mask.
+     *
+     * @param callCapabilities The {@code CallCapabilities} bit-mask.
+     * @return The capabilities with the add participant capabilities applied.
+     */
+    private int applyAddParticipantCapabilities(int callCapabilities) {
+        int currentCapabilities = callCapabilities;
+        if (isAddParticipantCapable()) {
+            currentCapabilities = changeBitmask(currentCapabilities,
+                    Connection.CAPABILITY_ADD_PARTICIPANT, true);
+        } else {
+            currentCapabilities = changeBitmask(currentCapabilities,
+                    Connection.CAPABILITY_ADD_PARTICIPANT, false);
+        }
+        return currentCapabilities;
+    }
+
     @VisibleForTesting
     public PersistableBundle getCarrierConfig() {
         Phone phone = getPhone();
@@ -1540,6 +1763,50 @@
         return false;
     }
 
+    private boolean isCallTransferSupported() {
+        PersistableBundle b = getCarrierConfig();
+        // Return false if the CarrierConfig is unavailable
+        if (b != null) {
+            return b.getBoolean(CarrierConfigManager.KEY_CARRIER_ALLOW_TRANSFER_IMS_CALL_BOOL);
+        }
+        return false;
+    }
+
+    private boolean canTransfer(TelephonyConnection c) {
+        com.android.internal.telephony.Connection connection = c.getOriginalConnection();
+        return (connection != null && !connection.isMultiparty()
+                && (c.getState() == STATE_ACTIVE || c.getState() == STATE_HOLDING));
+    }
+
+    private boolean canTransferToNumber() {
+        if (!isCallTransferSupported()) {
+            return false;
+        }
+        return canTransfer(this);
+    }
+
+    private boolean canConsultativeTransfer() {
+        if (!isCallTransferSupported()) {
+            return false;
+        }
+        if (!canTransfer(this)) {
+            return false;
+        }
+        boolean canConsultativeTransfer = false;
+        if (getTelephonyConnectionService() != null) {
+            for (Connection current : getTelephonyConnectionService().getAllConnections()) {
+                if (current != this && current instanceof TelephonyConnection) {
+                    TelephonyConnection other = (TelephonyConnection) current;
+                    if (canTransfer(other)) {
+                        canConsultativeTransfer = true;
+                        break;
+                    }
+                }
+            }
+        }
+        return canConsultativeTransfer;
+    }
+
     /**
      * Determines if the device will respect the value of the
      * {@link CarrierConfigManager#KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL} configuration option.
@@ -1628,6 +1895,46 @@
         }
     }
 
+    protected void reject(@android.telecom.Call.RejectReason int rejectReason) {
+        if (mOriginalConnection != null) {
+            mHangupDisconnectCause = android.telephony.DisconnectCause.INCOMING_REJECTED;
+            try {
+                // Hanging up a ringing call requires that we invoke call.hangup() as opposed to
+                // connection.hangup(). Without this change, the party originating the call
+                // will not get sent to voicemail if the user opts to reject the call.
+                if (isValidRingingCall()) {
+                    Call call = getCall();
+                    if (call != null) {
+                        call.hangup(rejectReason);
+                    } else {
+                        Log.w(this, "Attempting to hangup a connection without backing call.");
+                    }
+                } else {
+                    // We still prefer to call connection.hangup() for non-ringing calls
+                    // in order to support hanging-up specific calls within a conference call.
+                    // If we invoked call.hangup() while in a conference, we would end up
+                    // hanging up the entire conference call instead of the specific connection.
+                    mOriginalConnection.hangup();
+                }
+            } catch (CallStateException e) {
+                Log.e(this, e, "Call to Connection.hangup failed with exception");
+            }
+        } else {
+            if (getState() == STATE_DISCONNECTED) {
+                Log.i(this, "hangup called on an already disconnected call!");
+                close();
+            } else {
+                // There are a few cases where mOriginalConnection has not been set yet. For
+                // example, when the radio has to be turned on to make an emergency call,
+                // mOriginalConnection could not be set for many seconds.
+                setTelephonyConnectionDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
+                        android.telephony.DisconnectCause.LOCAL,
+                        "Local Disconnect before connection established."));
+                close();
+            }
+        }
+    }
+
     com.android.internal.telephony.Connection getOriginalConnection() {
         return mOriginalConnection;
     }
@@ -1742,6 +2049,12 @@
 
                     // Ensure extras are propagated to Telecom.
                     putTelephonyExtras(mOriginalConnectionExtras);
+                    // If extras contain Conference support information,
+                    // then ensure capabilities are updated.
+                    if (mOriginalConnectionExtras.containsKey(
+                            ImsCallProfile.EXTRA_CONFERENCE_AVAIL)) {
+                        updateConnectionCapabilities();
+                    }
                 } else {
                     Log.d(this, "Extras update not required");
                 }
@@ -2530,6 +2843,8 @@
         }
         sb.append(" confSupported:");
         sb.append(mIsConferenceSupported ? "Y" : "N");
+        sb.append(" isAdhocConf:");
+        sb.append(isAdhocConferenceCall() ? "Y" : "N");
         sb.append("]");
         return sb.toString();
     }
@@ -2654,8 +2969,13 @@
      * <p>
      * Note: This should be used instead of {@link #setVideoState(int)} to ensure listeners are
      * notified.
+     * @param videoState The new video state. Valid values:
+     *                   {@link VideoProfile#STATE_AUDIO_ONLY},
+     *                   {@link VideoProfile#STATE_BIDIRECTIONAL},
+     *                   {@link VideoProfile#STATE_TX_ENABLED},
+     *                   {@link VideoProfile#STATE_RX_ENABLED}.
      */
-    public void setTelephonyVideoState(@VideoProfile.VideoState int videoState) {
+    public void setTelephonyVideoState(int videoState) {
         setVideoState(videoState);
         notifyVideoStateChanged(videoState);
     }
@@ -2846,15 +3166,29 @@
 
     /**
      * Notifies {@link TelephonyConnectionListener}s of a change to the video state of a connection.
-     * @param videoState The new video state.
+     * @param videoState The new video state. Valid values:
+     *                   {@link VideoProfile#STATE_AUDIO_ONLY},
+     *                   {@link VideoProfile#STATE_BIDIRECTIONAL},
+     *                   {@link VideoProfile#STATE_TX_ENABLED},
+     *                   {@link VideoProfile#STATE_RX_ENABLED}.
      */
-    private void notifyVideoStateChanged(@VideoProfile.VideoState int videoState) {
+    private void notifyVideoStateChanged(int videoState) {
         for (TelephonyConnectionListener listener : mTelephonyListeners) {
             listener.onVideoStateChanged(this, videoState);
         }
     }
 
     /**
+     * Notifies {@link TelephonyConnectionListener}s of a whether to play Ringback Tone or not.
+     * @param ringback Whether the ringback tone is to be played
+     */
+    private void notifyRingbackRequested(boolean ringback) {
+        for (TelephonyConnectionListener listener : mTelephonyListeners) {
+            listener.onRingbackRequested(this, ringback);
+        }
+    }
+
+    /**
      * Notifies {@link TelephonyConnectionListener}s of changes to the video provider for a
      * connection.
      * @param videoProvider The new video provider.
@@ -2875,4 +3209,29 @@
             listener.onStatusHintsChanged(this, statusHints);
         }
     }
+
+    /**
+     * Whether the incoming call number should be formatted to national number for Japan.
+     * @return {@code true} should be convert to the national format, {@code false} otherwise.
+     */
+    private boolean isNeededToFormatIncomingNumberForJp() {
+        if (mOriginalConnection.isIncoming()
+                && !TextUtils.isEmpty(mOriginalConnection.getAddress())
+                && mOriginalConnection.getAddress().startsWith(JAPAN_COUNTRY_CODE_WITH_PLUS_SIGN)) {
+            PersistableBundle b = getCarrierConfig();
+            return b != null && b.getBoolean(
+                    CarrierConfigManager.KEY_FORMAT_INCOMING_NUMBER_TO_NATIONAL_FOR_JP_BOOL);
+        }
+        return false;
+    }
+
+    /**
+     * Format the incoming call number to national number for Japan.
+     * @param number
+     * @return the formatted phone number (e.g, "+819012345678" -> "09012345678")
+     */
+    private String formatIncomingNumberForJp(String number) {
+        return PhoneNumberUtils.stripSeparators(
+                PhoneNumberUtils.formatNumber(number, JAPAN_ISO_COUNTRY_CODE));
+    }
 }
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 40b941e..665bf22 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -17,10 +17,13 @@
 package com.android.services.telephony;
 
 import android.annotation.NonNull;
+import android.app.AlertDialog;
+import android.app.Dialog;
 import android.content.ActivityNotFoundException;
 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.net.Uri;
@@ -46,6 +49,7 @@
 import android.telephony.emergency.EmergencyNumber;
 import android.text.TextUtils;
 import android.util.Pair;
+import android.view.WindowManager;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.Call;
@@ -65,12 +69,14 @@
 import com.android.phone.MMIDialogActivity;
 import com.android.phone.PhoneUtils;
 import com.android.phone.R;
+import com.android.phone.settings.SuppServicesUiUtil;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -246,12 +252,20 @@
 
         @Override
         public boolean isCurrentEmergencyNumber(String number) {
-            return mTelephonyManager.isEmergencyNumber(number);
+            try {
+                return mTelephonyManager.isEmergencyNumber(number);
+            } catch (IllegalStateException ise) {
+                return false;
+            }
         }
 
         @Override
         public Map<Integer, List<EmergencyNumber>> getCurrentEmergencyNumberList() {
-            return mTelephonyManager.getEmergencyNumberList();
+            try {
+                return mTelephonyManager.getEmergencyNumberList();
+            } catch (IllegalStateException ise) {
+                return new HashMap<>();
+            }
         }
     }
 
@@ -421,6 +435,14 @@
     }
 
     /**
+     * Overrides radioOnHelper for testing.
+     */
+    @VisibleForTesting
+    public void setRadioOnHelper(RadioOnHelper radioOnHelper) {
+        mRadioOnHelper = radioOnHelper;
+    }
+
+    /**
      * Overrides PhoneSwitcher dependencies for testing.
      */
     @VisibleForTesting
@@ -516,6 +538,136 @@
         return super.onUnbind(intent);
     }
 
+    private Conference placeOutgoingConference(ConnectionRequest request,
+            Connection resultConnection, Phone phone) {
+        if (resultConnection instanceof TelephonyConnection) {
+            return placeOutgoingConference((TelephonyConnection) resultConnection, phone, request);
+        }
+        return null;
+    }
+
+    private Conference placeOutgoingConference(TelephonyConnection conferenceHostConnection,
+            Phone phone, ConnectionRequest request) {
+        updatePhoneAccount(conferenceHostConnection, phone);
+        com.android.internal.telephony.Connection originalConnection = null;
+        try {
+            originalConnection = phone.startConference(
+                    getParticipantsToDial(request.getParticipants()),
+                    new ImsPhone.ImsDialArgs.Builder()
+                    .setVideoState(request.getVideoState())
+                    .setRttTextStream(conferenceHostConnection.getRttTextStream())
+                    .build());
+        } catch (CallStateException e) {
+            Log.e(this, e, "placeOutgoingConference, phone.startConference exception: " + e);
+            handleCallStateException(e, conferenceHostConnection, phone);
+            return null;
+        }
+
+        if (originalConnection == null) {
+            Log.d(this, "placeOutgoingConference, phone.startConference returned null");
+            conferenceHostConnection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
+                    android.telephony.DisconnectCause.OUTGOING_FAILURE,
+                    "conferenceHostConnection is null",
+                    phone.getPhoneId()));
+            conferenceHostConnection.clearOriginalConnection();
+            conferenceHostConnection.destroy();
+        } else {
+            conferenceHostConnection.setOriginalConnection(originalConnection);
+        }
+
+        return prepareConference(conferenceHostConnection, request.getAccountHandle());
+    }
+
+    Conference prepareConference(Connection conn, PhoneAccountHandle phoneAccountHandle) {
+        if (!(conn instanceof TelephonyConnection)) {
+            Log.w(this, "prepareConference returning NULL conference");
+            return null;
+        }
+
+        TelephonyConnection connection = (TelephonyConnection)conn;
+        ImsConference conference = new ImsConference(TelecomAccountRegistry.getInstance(this),
+                mTelephonyConnectionServiceProxy, connection,
+                phoneAccountHandle, () -> true);
+        mImsConferenceController.addConference(conference);
+        conference.setVideoState(connection,
+                connection.getVideoState());
+        conference.setVideoProvider(connection,
+                connection.getVideoProvider());
+        conference.setStatusHints(connection.getStatusHints());
+        conference.setAddress(connection.getAddress(),
+                connection.getAddressPresentation());
+        conference.setCallerDisplayName(connection.getCallerDisplayName(),
+                connection.getCallerDisplayNamePresentation());
+        conference.setParticipants(connection.getParticipants());
+        return conference;
+    }
+
+    @Override
+    public @Nullable Conference onCreateIncomingConference(
+            @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
+            @NonNull final ConnectionRequest request) {
+        Log.i(this, "onCreateIncomingConference, request: " + request);
+        Connection connection = onCreateIncomingConnection(connectionManagerPhoneAccount, request);
+        Log.d(this, "onCreateIncomingConference, connection: %s", connection);
+        if (connection == null) {
+            Log.i(this, "onCreateIncomingConference, implementation returned null connection.");
+            return Conference.createFailedConference(
+                    new DisconnectCause(DisconnectCause.ERROR, "IMPL_RETURNED_NULL_CONNECTION"),
+                    request.getAccountHandle());
+        }
+
+        final Phone phone = getPhoneForAccount(request.getAccountHandle(),
+                false /* isEmergencyCall*/, null /* not an emergency call */);
+        if (phone == null) {
+            Log.d(this, "onCreateIncomingConference, phone is null");
+            return Conference.createFailedConference(
+                    DisconnectCauseUtil.toTelecomDisconnectCause(
+                            android.telephony.DisconnectCause.OUT_OF_SERVICE,
+                            "Phone is null"),
+                    request.getAccountHandle());
+        }
+
+        return prepareConference(connection, request.getAccountHandle());
+    }
+
+    @Override
+    public @Nullable Conference onCreateOutgoingConference(
+            @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
+            @NonNull final ConnectionRequest request) {
+        Log.i(this, "onCreateOutgoingConference, request: " + request);
+        Connection connection = onCreateOutgoingConnection(connectionManagerPhoneAccount, request);
+        Log.d(this, "onCreateOutgoingConference, connection: %s", connection);
+        if (connection == null) {
+            Log.i(this, "onCreateOutgoingConference, implementation returned null connection.");
+            return Conference.createFailedConference(
+                    new DisconnectCause(DisconnectCause.ERROR, "IMPL_RETURNED_NULL_CONNECTION"),
+                    request.getAccountHandle());
+        }
+
+        final Phone phone = getPhoneForAccount(request.getAccountHandle(),
+                false /* isEmergencyCall*/, null /* not an emergency call */);
+        if (phone == null) {
+            Log.d(this, "onCreateOutgoingConference, phone is null");
+            return Conference.createFailedConference(
+                    DisconnectCauseUtil.toTelecomDisconnectCause(
+                            android.telephony.DisconnectCause.OUT_OF_SERVICE,
+                            "Phone is null"),
+                    request.getAccountHandle());
+        }
+
+        return placeOutgoingConference(request, connection, phone);
+    }
+
+    private String[] getParticipantsToDial(List<Uri> participants) {
+        String[] participantsToDial = new String[participants.size()];
+        int i = 0;
+        for (Uri participant : participants) {
+           participantsToDial[i] = participant.getSchemeSpecificPart();
+           i++;
+        }
+        return participantsToDial;
+    }
+
     @Override
     public Connection onCreateOutgoingConnection(
             PhoneAccountHandle connectionManagerPhoneAccount,
@@ -523,7 +675,9 @@
         Log.i(this, "onCreateOutgoingConnection, request: " + request);
 
         Uri handle = request.getAddress();
-        if (handle == null) {
+        boolean isAdhocConference = request.isAdhocConferenceCall();
+
+        if (!isAdhocConference && handle == null) {
             Log.d(this, "onCreateOutgoingConnection, handle is null");
             return Connection.createFailedConnection(
                     mDisconnectCauseFactory.toTelecomDisconnectCause(
@@ -626,19 +780,21 @@
         }
         final String numberToDial = number;
 
-
         final boolean isAirplaneModeOn = mDeviceState.isAirplaneModeOn(this);
 
         boolean needToTurnOnRadio = (isEmergencyNumber && (!isRadioOn() || isAirplaneModeOn))
                 || isRadioPowerDownOnBluetooth();
 
+        // Get the right phone object from the account data passed in.
+        final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber,
+                /* Note: when not an emergency, handle can be null for unknown callers */
+                handle == null ? null : handle.getSchemeSpecificPart());
+
         if (needToTurnOnRadio) {
             final Uri resultHandle = handle;
-            // By default, Connection based on the default Phone, since we need to return to Telecom
-            // now.
-            final int originalPhoneType = mPhoneFactoryProxy.getDefaultPhone().getPhoneType();
+            final int originalPhoneType = phone.getPhoneType();
             final Connection resultConnection = getTelephonyConnection(request, numberToDial,
-                    isEmergencyNumber, resultHandle, PhoneFactory.getDefaultPhone());
+                    isEmergencyNumber, resultHandle, phone);
             if (mRadioOnHelper == null) {
                 mRadioOnHelper = new RadioOnHelper(this);
             }
@@ -646,7 +802,7 @@
                 @Override
                 public void onComplete(RadioOnStateListener listener, boolean isRadioReady) {
                     handleOnComplete(isRadioReady, isEmergencyNumber, resultConnection, request,
-                            numberToDial, resultHandle, originalPhoneType);
+                            numberToDial, resultHandle, originalPhoneType, phone);
                 }
 
                 @Override
@@ -662,7 +818,7 @@
                         // been powered on and isn't in the UNAVAILABLE state, even if it is
                         // reporting the OUT_OF_SERVICE state.
                         return (phone.getState() == PhoneConstants.State.OFFHOOK)
-                            || phone.getServiceState().getState() != ServiceState.STATE_POWER_OFF;
+                            || phone.getServiceStateTracker().isRadioOn();
                     } else {
                         // Wait until we are in service and ready to make calls. This can happen
                         // when we power down the radio on bluetooth to save power on watches or if
@@ -675,7 +831,7 @@
                                 || serviceState == ServiceState.STATE_IN_SERVICE;
                     }
                 }
-            });
+            }, isEmergencyNumber && !isTestEmergencyNumber, phone);
             // Return the still unconnected GsmConnection and wait for the Radios to boot before
             // connecting it to the underlying Phone.
             return resultConnection;
@@ -691,14 +847,18 @@
                                 "Add call restricted due to ongoing video call"));
             }
 
-            // Get the right phone object from the account data passed in.
-            final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber,
-                    /* Note: when not an emergency, handle can be null for unknown callers */
-                    handle == null ? null : handle.getSchemeSpecificPart());
             if (!isEmergencyNumber) {
                 final Connection resultConnection = getTelephonyConnection(request, numberToDial,
                         false, handle, phone);
-                return placeOutgoingConnection(request, resultConnection, phone);
+                if (isAdhocConference) {
+                    if (resultConnection instanceof TelephonyConnection) {
+                        TelephonyConnection conn = (TelephonyConnection)resultConnection;
+                        conn.setParticipants(request.getParticipants());
+                    }
+                    return resultConnection;
+                } else {
+                    return placeOutgoingConnection(request, resultConnection, phone);
+                }
             } else {
                 final Connection resultConnection = getTelephonyConnection(request, numberToDial,
                         true, handle, phone);
@@ -763,18 +923,21 @@
      */
     private void handleOnComplete(boolean isRadioReady, boolean isEmergencyNumber,
             Connection originalConnection, ConnectionRequest request, String numberToDial,
-            Uri handle, int originalPhoneType) {
+            Uri handle, int originalPhoneType, Phone phone) {
         // Make sure the Call has not already been canceled by the user.
         if (originalConnection.getState() == Connection.STATE_DISCONNECTED) {
             Log.i(this, "Call disconnected before the outgoing call was placed. Skipping call "
                     + "placement.");
+            if (isEmergencyNumber) {
+                // If call is already canceled by the user, notify modem to exit emergency call
+                // mode by sending radio on with forEmergencyCall=false.
+                for (Phone curPhone : mPhoneFactoryProxy.getPhones()) {
+                    curPhone.setRadioPower(true, false, false, true);
+                }
+            }
             return;
         }
-        // Get the right phone object since the radio has been turned on successfully.
         if (isRadioReady) {
-            final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber,
-                    /* Note: when not an emergency, handle can be null for unknown callers */
-                    handle == null ? null : handle.getSchemeSpecificPart());
             if (!isEmergencyNumber) {
                 adjustAndPlaceOutgoingConnection(phone, originalConnection, request, numberToDial,
                         handle, originalPhoneType, false);
@@ -816,7 +979,8 @@
             // TODO: Switch out the underlying connection instead of creating a new
             // one and causing UI Jank.
             boolean noActiveSimCard = SubscriptionController.getInstance()
-                    .getActiveSubInfoCount(phone.getContext().getOpPackageName()) == 0;
+                    .getActiveSubInfoCount(phone.getContext().getOpPackageName(),
+                            null) == 0;
             // If there's no active sim card and the device is in emergency mode, use E account.
             addExistingConnection(mPhoneUtilsProxy.makePstnPhoneAccountHandleWithPrefix(
                     phone, "", isEmergencyNumber && noActiveSimCard), repConnection);
@@ -895,7 +1059,7 @@
             int dataNetType = phone.getServiceState().getDataNetworkType();
             if (dataNetType == TelephonyManager.NETWORK_TYPE_LTE ||
                     dataNetType == TelephonyManager.NETWORK_TYPE_LTE_CA) {
-                state = phone.getServiceState().getDataRegState();
+                state = phone.getServiceState().getDataRegistrationState();
             }
         }
 
@@ -981,7 +1145,7 @@
 
         final TelephonyConnection connection =
                 createConnectionFor(phone, null, true /* isOutgoing */, request.getAccountHandle(),
-                        request.getTelecomCallId());
+                        request.getTelecomCallId(), request.isAdhocConferenceCall());
         if (connection == null) {
             return Connection.createFailedConnection(
                     mDisconnectCauseFactory.toTelecomDisconnectCause(
@@ -994,6 +1158,8 @@
         connection.setTelephonyVideoState(request.getVideoState());
         connection.setRttTextStream(request.getRttTextStream());
         connection.setTtyEnabled(isTtyModeEnabled);
+        connection.setIsAdhocConferenceCall(request.isAdhocConferenceCall());
+        connection.setParticipants(request.getParticipants());
         return connection;
     }
 
@@ -1025,11 +1191,26 @@
         Call call = phone.getRingingCall();
         if (!call.getState().isRinging()) {
             Log.i(this, "onCreateIncomingConnection, no ringing call");
-            return Connection.createFailedConnection(
+            Connection connection = Connection.createFailedConnection(
                     mDisconnectCauseFactory.toTelecomDisconnectCause(
                             android.telephony.DisconnectCause.INCOMING_MISSED,
                             "Found no ringing call",
                             phone.getPhoneId()));
+            Bundle extras = request.getExtras();
+
+            long time = extras.getLong(TelecomManager.EXTRA_CALL_CREATED_EPOCH_TIME_MILLIS);
+            if (time != 0) {
+                Log.i(this, "onCreateIncomingConnection. Set connect time info.");
+                connection.setConnectTimeMillis(time);
+            }
+
+            Uri address = extras.getParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS);
+            if (address != null) {
+                Log.i(this, "onCreateIncomingConnection. Set caller id info.");
+                connection.setAddress(address, TelecomManager.PRESENTATION_ALLOWED);
+            }
+
+            return connection;
         }
 
         com.android.internal.telephony.Connection originalConnection =
@@ -1042,7 +1223,8 @@
 
         TelephonyConnection connection =
                 createConnectionFor(phone, originalConnection, false /* isOutgoing */,
-                        request.getAccountHandle(), request.getTelecomCallId());
+                        request.getAccountHandle(), request.getTelecomCallId(),
+                        request.isAdhocConferenceCall());
         handleIncomingRtt(request, originalConnection);
         if (connection == null) {
             return Connection.createCanceledConnection();
@@ -1154,6 +1336,29 @@
         connection.close();
     }
 
+    /**
+     * Called by the {@link ConnectionService} when a newly created {@link Conference} has been
+     * added to the {@link ConnectionService} and sent to Telecom.  Here it is safe to send
+     * connection events.
+     *
+     * @param conference the {@link Conference}.
+     */
+    @Override
+    public void onCreateConferenceComplete(Conference conference) {
+        if (conference instanceof ImsConference) {
+            ImsConference imsConference = (ImsConference)conference;
+            TelephonyConnection telephonyConnection =
+                    (TelephonyConnection)(imsConference.getConferenceHost());
+            maybeSendInternationalCallEvent(telephonyConnection);
+        }
+    }
+
+    public void onCreateIncomingConferenceFailed(PhoneAccountHandle connectionManagerPhoneAccount,
+            ConnectionRequest request) {
+        Log.i(this, "onCreateIncomingConferenceFailed, request: " + request);
+        onCreateIncomingConnectionFailed(connectionManagerPhoneAccount, request);
+    }
+
     @Override
     public void triggerConferenceRecalculate() {
         if (mTelephonyConferenceController.shouldRecalculate()) {
@@ -1450,6 +1655,12 @@
             TelephonyConnection connection, Phone phone, int videoState, Bundle extras) {
         String number = connection.getAddress().getSchemeSpecificPart();
 
+        if (showDataDialog(phone, number)) {
+            connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
+                        android.telephony.DisconnectCause.DIALED_MMI, "UT is not available"));
+            return;
+        }
+
         com.android.internal.telephony.Connection originalConnection = null;
         try {
             if (phone != null) {
@@ -1470,6 +1681,12 @@
                                                     .OUTGOING_EMERGENCY_CALL_PLACED);
                                 }
                             }
+                            for (Conference c : getAllConferences()) {
+                                if (c.getState() != Connection.STATE_DISCONNECTED
+                                        && c instanceof Conference) {
+                                    ((Conference) c).onDisconnect();
+                                }
+                            }
                         } else if (!isVideoCallHoldAllowed(phone)) {
                             // If we do not support holding ongoing video call for an outgoing
                             // emergency call, disconnect the ongoing video call.
@@ -1495,34 +1712,7 @@
             }
         } catch (CallStateException e) {
             Log.e(this, e, "placeOutgoingConnection, phone.dial exception: " + e);
-            int cause = android.telephony.DisconnectCause.OUTGOING_FAILURE;
-            switch (e.getError()) {
-                case CallStateException.ERROR_OUT_OF_SERVICE:
-                    cause = android.telephony.DisconnectCause.OUT_OF_SERVICE;
-                    break;
-                case CallStateException.ERROR_POWER_OFF:
-                    cause = android.telephony.DisconnectCause.POWER_OFF;
-                    break;
-                case CallStateException.ERROR_ALREADY_DIALING:
-                    cause = android.telephony.DisconnectCause.ALREADY_DIALING;
-                    break;
-                case CallStateException.ERROR_CALL_RINGING:
-                    cause = android.telephony.DisconnectCause.CANT_CALL_WHILE_RINGING;
-                    break;
-                case CallStateException.ERROR_CALLING_DISABLED:
-                    cause = android.telephony.DisconnectCause.CALLING_DISABLED;
-                    break;
-                case CallStateException.ERROR_TOO_MANY_CALLS:
-                    cause = android.telephony.DisconnectCause.TOO_MANY_ONGOING_CALLS;
-                    break;
-                case CallStateException.ERROR_OTASP_PROVISIONING_IN_PROCESS:
-                    cause = android.telephony.DisconnectCause.OTASP_PROVISIONING_IN_PROCESS;
-                    break;
-            }
-            connection.setTelephonyConnectionDisconnected(
-                    mDisconnectCauseFactory.toTelecomDisconnectCause(cause, e.getMessage(),
-                            phone.getPhoneId()));
-            connection.close();
+            handleCallStateException(e, connection, phone);
             return;
         }
 
@@ -1538,7 +1728,7 @@
                 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                         Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                 if (SubscriptionManager.isValidSubscriptionId(subId)) {
-                    intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
+                    SubscriptionManager.putSubscriptionIdExtra(intent, subId);
                 }
                 startActivity(intent);
             }
@@ -1561,7 +1751,7 @@
             return true;
         }
         return cfgManager.getConfigForSubId(phone.getSubId()).getBoolean(
-                CarrierConfigManager.KEY_ALLOW_HOLDING_VIDEO_CALL_BOOL, true);
+                CarrierConfigManager.KEY_ALLOW_HOLD_VIDEO_CALL_BOOL, true);
     }
 
     private boolean shouldHoldForEmergencyCall(Phone phone) {
@@ -1576,12 +1766,55 @@
                 CarrierConfigManager.KEY_ALLOW_HOLD_CALL_DURING_EMERGENCY_BOOL, true);
     }
 
+    private void handleCallStateException(CallStateException e, TelephonyConnection connection,
+            Phone phone) {
+        int cause = android.telephony.DisconnectCause.OUTGOING_FAILURE;
+        switch (e.getError()) {
+            case CallStateException.ERROR_OUT_OF_SERVICE:
+                cause = android.telephony.DisconnectCause.OUT_OF_SERVICE;
+                break;
+            case CallStateException.ERROR_POWER_OFF:
+                 cause = android.telephony.DisconnectCause.POWER_OFF;
+                 break;
+            case CallStateException.ERROR_ALREADY_DIALING:
+                 cause = android.telephony.DisconnectCause.ALREADY_DIALING;
+                 break;
+            case CallStateException.ERROR_CALL_RINGING:
+                 cause = android.telephony.DisconnectCause.CANT_CALL_WHILE_RINGING;
+                 break;
+            case CallStateException.ERROR_CALLING_DISABLED:
+                 cause = android.telephony.DisconnectCause.CALLING_DISABLED;
+                 break;
+            case CallStateException.ERROR_TOO_MANY_CALLS:
+                 cause = android.telephony.DisconnectCause.TOO_MANY_ONGOING_CALLS;
+                 break;
+            case CallStateException.ERROR_OTASP_PROVISIONING_IN_PROCESS:
+                 cause = android.telephony.DisconnectCause.OTASP_PROVISIONING_IN_PROCESS;
+                 break;
+        }
+        connection.setTelephonyConnectionDisconnected(
+                DisconnectCauseUtil.toTelecomDisconnectCause(cause, e.getMessage(),
+                        phone.getPhoneId()));
+        connection.close();
+    }
+
     private TelephonyConnection createConnectionFor(
             Phone phone,
             com.android.internal.telephony.Connection originalConnection,
             boolean isOutgoing,
             PhoneAccountHandle phoneAccountHandle,
             String telecomCallId) {
+            return createConnectionFor(phone, originalConnection, isOutgoing, phoneAccountHandle,
+                    telecomCallId, false);
+    }
+
+    private TelephonyConnection createConnectionFor(
+            Phone phone,
+            com.android.internal.telephony.Connection originalConnection,
+            boolean isOutgoing,
+            PhoneAccountHandle phoneAccountHandle,
+            String telecomCallId,
+            boolean isAdhocConference) {
         TelephonyConnection returnConnection = null;
         int phoneType = phone.getPhoneType();
         if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
@@ -1592,8 +1825,10 @@
                     allowsMute, isOutgoing, telecomCallId);
         }
         if (returnConnection != null) {
-            // Listen to Telephony specific callbacks from the connection
-            returnConnection.addTelephonyConnectionListener(mTelephonyConnectionListener);
+            if (!isAdhocConference) {
+                // Listen to Telephony specific callbacks from the connection
+                returnConnection.addTelephonyConnectionListener(mTelephonyConnectionListener);
+            }
             returnConnection.setVideoPauseSupported(
                     TelecomAccountRegistry.getInstance(this).isVideoPauseSupported(
                             phoneAccountHandle));
@@ -2133,6 +2368,78 @@
         }
     }
 
+    private boolean showDataDialog(Phone phone, String number) {
+        boolean ret = false;
+        final Context context = getApplicationContext();
+        String suppKey = MmiCodeUtil.getSuppServiceKey(number);
+        if (suppKey != null) {
+            boolean clirOverUtPrecautions = false;
+            boolean cfOverUtPrecautions = false;
+            boolean cbOverUtPrecautions = false;
+            boolean cwOverUtPrecautions = false;
+
+            CarrierConfigManager cfgManager = (CarrierConfigManager)
+                phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
+            if (cfgManager != null) {
+                clirOverUtPrecautions = cfgManager.getConfigForSubId(phone.getSubId())
+                    .getBoolean(CarrierConfigManager.KEY_CALLER_ID_OVER_UT_WARNING_BOOL);
+                cfOverUtPrecautions = cfgManager.getConfigForSubId(phone.getSubId())
+                    .getBoolean(CarrierConfigManager.KEY_CALL_FORWARDING_OVER_UT_WARNING_BOOL);
+                cbOverUtPrecautions = cfgManager.getConfigForSubId(phone.getSubId())
+                    .getBoolean(CarrierConfigManager.KEY_CALL_BARRING_OVER_UT_WARNING_BOOL);
+                cwOverUtPrecautions = cfgManager.getConfigForSubId(phone.getSubId())
+                    .getBoolean(CarrierConfigManager.KEY_CALL_WAITING_OVER_UT_WARNING_BOOL);
+            }
+
+            boolean isSsOverUtPrecautions = SuppServicesUiUtil
+                .isSsOverUtPrecautions(context, phone);
+            if (isSsOverUtPrecautions) {
+                boolean showDialog = false;
+                if (suppKey == MmiCodeUtil.BUTTON_CLIR_KEY && clirOverUtPrecautions) {
+                    showDialog = true;
+                } else if (suppKey == MmiCodeUtil.CALL_FORWARDING_KEY && cfOverUtPrecautions) {
+                    showDialog = true;
+                } else if (suppKey == MmiCodeUtil.CALL_BARRING_KEY && cbOverUtPrecautions) {
+                    showDialog = true;
+                } else if (suppKey == MmiCodeUtil.BUTTON_CW_KEY && cwOverUtPrecautions) {
+                    showDialog = true;
+                }
+
+                if (showDialog) {
+                    Log.d(this, "Creating UT Data enable dialog");
+                    String message = SuppServicesUiUtil.makeMessage(context, suppKey, phone);
+                    AlertDialog.Builder builder = new AlertDialog.Builder(context);
+                    DialogInterface.OnClickListener networkSettingsClickListener =
+                            new Dialog.OnClickListener() {
+                                @Override
+                                public void onClick(DialogInterface dialog, int which) {
+                                    Intent intent = new Intent(Intent.ACTION_MAIN);
+                                    ComponentName mobileNetworkSettingsComponent
+                                        = new ComponentName(
+                                                context.getString(
+                                                    R.string.mobile_network_settings_package),
+                                                context.getString(
+                                                    R.string.mobile_network_settings_class));
+                                    intent.setComponent(mobileNetworkSettingsComponent);
+                                    context.startActivity(intent);
+                                }
+                            };
+                    Dialog dialog = builder.setMessage(message)
+                        .setNeutralButton(context.getResources().getString(
+                                R.string.settings_label),
+                                networkSettingsClickListener)
+                        .setPositiveButton(context.getResources().getString(
+                                R.string.supp_service_over_ut_precautions_dialog_dismiss), null)
+                        .create();
+                    dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+                    dialog.show();
+                    ret = true;
+                }
+            }
+        }
+        return ret;
+    }
+
     /**
      * Adds a {@link Conference} to the telephony ConnectionService and registers a listener for
      * changes to the conference.  Should be used instead of {@link #addConference(Conference)}.
diff --git a/src/com/android/services/telephony/rcs/RcsFeatureController.java b/src/com/android/services/telephony/rcs/RcsFeatureController.java
new file mode 100644
index 0000000..5094c57
--- /dev/null
+++ b/src/com/android/services/telephony/rcs/RcsFeatureController.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2020 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.rcs;
+
+import android.annotation.AnyThread;
+import android.content.Context;
+import android.net.Uri;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.ImsRcsManager;
+import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.RegistrationManager;
+import android.telephony.ims.aidl.IImsCapabilityCallback;
+import android.telephony.ims.aidl.IImsRegistrationCallback;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.ims.FeatureConnector;
+import com.android.ims.IFeatureConnector;
+import com.android.ims.RcsFeatureManager;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.imsphone.ImsRegistrationCallbackHelper;
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * Contains the RCS feature implementations that are associated with this slot's RcsFeature.
+ */
+@AnyThread
+public class RcsFeatureController {
+    private static final String LOG_TAG = "RcsFeatureController";
+
+    /**
+     * Interface used by RCS features that need to listen for when the associated service has been
+     * connected.
+     */
+    public interface Feature {
+        /**
+         * The RcsFeature has been connected to the framework and is ready.
+         */
+        void onRcsConnected(RcsFeatureManager manager);
+
+        /**
+         * The framework has lost the binding to the RcsFeature or it is in the process of changing.
+         */
+        void onRcsDisconnected();
+
+        /**
+         * The subscription associated with the slot this controller is bound to has changed or its
+         * carrier configuration has changed.
+         */
+        void onAssociatedSubscriptionUpdated(int subId);
+
+        /**
+         * Called when the feature should be destroyed.
+         */
+        void onDestroy();
+    }
+
+    /**
+     * Used to inject FeatureConnector instances for testing.
+     */
+    @VisibleForTesting
+    public interface FeatureConnectorFactory<T extends IFeatureConnector> {
+        /**
+         * @return a {@link FeatureConnector} associated for the given {@link IFeatureConnector}
+         * and slot id.
+         */
+        FeatureConnector<T> create(Context context, int slotId,
+                FeatureConnector.Listener<T> listener, Executor executor, String tag);
+    }
+
+    /**
+     * Used to inject ImsRegistrationCallbackHelper instances for testing.
+     */
+    @VisibleForTesting
+    public interface RegistrationHelperFactory {
+        /**
+         * @return an {@link ImsRegistrationCallbackHelper}, which helps manage IMS registration
+         * state.
+         */
+        ImsRegistrationCallbackHelper create(
+                ImsRegistrationCallbackHelper.ImsRegistrationUpdate cb, Executor executor);
+    }
+
+    private FeatureConnectorFactory<RcsFeatureManager> mFeatureFactory = FeatureConnector::new;
+    private RegistrationHelperFactory mRegistrationHelperFactory =
+            ImsRegistrationCallbackHelper::new;
+
+    private final Map<Class<?>, Feature> mFeatures = new ArrayMap<>();
+    private final Context mContext;
+    private final ImsRegistrationCallbackHelper mImsRcsRegistrationHelper;
+    private final int mSlotId;
+    private final Object mLock = new Object();
+    private FeatureConnector<RcsFeatureManager> mFeatureConnector;
+    private RcsFeatureManager mFeatureManager;
+
+    private FeatureConnector.Listener<RcsFeatureManager> mFeatureConnectorListener =
+            new FeatureConnector.Listener<RcsFeatureManager>() {
+                @Override
+                public RcsFeatureManager getFeatureManager() {
+                    return new RcsFeatureManager(mContext, mSlotId);
+                }
+
+                @Override
+                public void connectionReady(RcsFeatureManager manager)
+                        throws com.android.ims.ImsException {
+                    if (manager == null) {
+                        logw("connectionReady returned null RcsFeatureManager");
+                        return;
+                    }
+                    try {
+                        // May throw ImsException if for some reason the connection to the
+                        // ImsService is gone.
+                        setupConnectionToService(manager);
+                    } catch (ImsException e) {
+                        // Use deprecated Exception for compatibility.
+                        throw new com.android.ims.ImsException(e.getMessage(),
+                                ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
+                    }
+                    updateConnectionStatus(manager);
+                }
+
+                @Override
+                public void connectionUnavailable() {
+                    // Call before disabling connection to manager.
+                    removeConnectionToService();
+                    updateConnectionStatus(null /*manager*/);
+                }
+            };
+
+    private ImsRegistrationCallbackHelper.ImsRegistrationUpdate mRcsRegistrationUpdate = new
+            ImsRegistrationCallbackHelper.ImsRegistrationUpdate() {
+                @Override
+                public void handleImsRegistered(int imsRadioTech) {
+                }
+
+                @Override
+                public void handleImsRegistering(int imsRadioTech) {
+                }
+
+                @Override
+                public void handleImsUnregistered(ImsReasonInfo imsReasonInfo) {
+                }
+
+                @Override
+                public void handleImsSubscriberAssociatedUriChanged(Uri[] uris) {
+                }
+            };
+
+    public RcsFeatureController(Context context, int slotId) {
+        mContext = context;
+        mSlotId = slotId;
+        mImsRcsRegistrationHelper = mRegistrationHelperFactory.create(mRcsRegistrationUpdate,
+                mContext.getMainExecutor());
+    }
+
+    /**
+     * Should only be used to inject registration helpers for testing.
+     */
+    @VisibleForTesting
+    public RcsFeatureController(Context context, int slotId, RegistrationHelperFactory f) {
+        mContext = context;
+        mSlotId = slotId;
+        mRegistrationHelperFactory = f;
+        mImsRcsRegistrationHelper = mRegistrationHelperFactory.create(mRcsRegistrationUpdate,
+                mContext.getMainExecutor());
+    }
+
+    /**
+     * This method should be called after constructing an instance of this class to start the
+     * connection process to the associated RcsFeature.
+     */
+    public void connect() {
+        synchronized (mLock) {
+            if (mFeatureConnector != null) return;
+            mFeatureConnector = mFeatureFactory.create(mContext, mSlotId, mFeatureConnectorListener,
+                    mContext.getMainExecutor(), LOG_TAG);
+            mFeatureConnector.connect();
+        }
+    }
+
+    /**
+     * Adds a {@link Feature} to be tracked by this FeatureController.
+     */
+    public <T extends Feature> void addFeature(T connector, Class<T> clazz) {
+        synchronized (mLock) {
+            mFeatures.put(clazz, connector);
+        }
+        RcsFeatureManager manager = getFeatureManager();
+        if (manager != null) {
+            connector.onRcsConnected(manager);
+        } else {
+            connector.onRcsDisconnected();
+        }
+    }
+
+    /**
+     * @return The RCS feature implementation tracked by this controller.
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T getFeature(Class<T> clazz) {
+        synchronized (mLock) {
+            return (T) mFeatures.get(clazz);
+        }
+    }
+
+    /**
+     * Removes the feature associated with this class.
+     */
+    public <T> void removeFeature(Class<T> clazz) {
+        synchronized (mLock) {
+            RcsFeatureController.Feature feature = mFeatures.remove(clazz);
+            feature.onDestroy();
+        }
+    }
+
+    /**
+     * @return true if this controller has features it is actively tracking.
+     */
+    public boolean hasActiveFeatures() {
+        synchronized (mLock) {
+            return mFeatures.size() > 0;
+        }
+    }
+
+    /**
+     * Update the subscription associated with this controller.
+     */
+    public void updateAssociatedSubscription(int newSubId) {
+        RcsFeatureManager manager = getFeatureManager();
+        if (manager != null) {
+            try {
+                manager.updateCapabilities();
+            } catch (ImsException e) {
+                Log.w(LOG_TAG, "associatedSubscriptionChanged failed:" + e);
+            }
+        }
+        synchronized (mLock) {
+            for (Feature c : mFeatures.values()) {
+                c.onAssociatedSubscriptionUpdated(newSubId);
+            }
+        }
+    }
+
+    /**
+     * Call before this controller is destroyed to tear down associated features.
+     */
+    public void destroy() {
+        synchronized (mLock) {
+            Log.i(LOG_TAG, "destroy: slotId=" + mSlotId);
+            if (mFeatureConnector != null) {
+                mFeatureConnector.disconnect();
+            }
+            for (Feature c : mFeatures.values()) {
+                c.onRcsDisconnected();
+                c.onDestroy();
+            }
+            mFeatures.clear();
+        }
+    }
+
+    @VisibleForTesting
+    public void setFeatureConnectorFactory(FeatureConnectorFactory factory) {
+        mFeatureFactory = factory;
+    }
+
+    /**
+     * Add a {@link RegistrationManager.RegistrationCallback} callback that gets called when IMS
+     * registration has changed for a specific subscription.
+     */
+    public void registerImsRegistrationCallback(int subId, IImsRegistrationCallback callback)
+            throws ImsException {
+        RcsFeatureManager manager = getFeatureManager();
+        if (manager == null) {
+            throw new ImsException("Service is not available",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
+        manager.registerImsRegistrationCallback(subId, callback);
+    }
+
+    /**
+     * Removes a previously registered {@link RegistrationManager.RegistrationCallback} callback
+     * that is associated with a specific subscription.
+     */
+    public void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback callback) {
+        RcsFeatureManager manager = getFeatureManager();
+        if (manager != null) {
+            manager.unregisterImsRegistrationCallback(subId, callback);
+        }
+    }
+
+    /**
+     * Register an {@link ImsRcsManager.AvailabilityCallback} with the associated RcsFeature,
+     * which will provide availability updates.
+     */
+    public void registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback)
+            throws ImsException {
+        RcsFeatureManager manager = getFeatureManager();
+        if (manager == null) {
+            throw new ImsException("Service is not available",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
+        manager.registerRcsAvailabilityCallback(subId, callback);
+    }
+
+    /**
+     * Remove a registered {@link ImsRcsManager.AvailabilityCallback} from the RcsFeature.
+     */
+    public void unregisterRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback) {
+        RcsFeatureManager manager = getFeatureManager();
+        if (manager != null) {
+            manager.unregisterRcsAvailabilityCallback(subId, callback);
+        }
+    }
+
+    /**
+     * Query for the specific capability.
+     */
+    public boolean isCapable(int capability, int radioTech)
+            throws android.telephony.ims.ImsException {
+        RcsFeatureManager manager = getFeatureManager();
+        if (manager == null) {
+            throw new ImsException("Service is not available",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
+        return manager.isCapable(capability, radioTech);
+    }
+
+    /**
+     * Query the availability of an IMS RCS capability.
+     */
+    public boolean isAvailable(int capability) throws android.telephony.ims.ImsException {
+        RcsFeatureManager manager = getFeatureManager();
+        if (manager == null) {
+            throw new ImsException("Service is not available",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
+        return manager.isAvailable(capability);
+    }
+
+    /**
+     * Get the IMS RCS registration technology for this Phone.
+     */
+    public void getRegistrationTech(Consumer<Integer> callback) {
+        RcsFeatureManager manager = getFeatureManager();
+        if (manager != null) {
+            manager.getImsRegistrationTech(callback);
+        }
+        callback.accept(ImsRegistrationImplBase.REGISTRATION_TECH_NONE);
+    }
+
+    /**
+     * Retrieve the current RCS registration state.
+     */
+    public void getRegistrationState(Consumer<Integer> callback) {
+        callback.accept(mImsRcsRegistrationHelper.getImsRegistrationState());
+    }
+
+    private void setupConnectionToService(RcsFeatureManager manager) throws ImsException {
+        // Open persistent listener connection, sends RcsFeature#onFeatureReady.
+        manager.openConnection();
+        manager.updateCapabilities();
+        manager.registerImsRegistrationCallback(mImsRcsRegistrationHelper.getCallbackBinder());
+    }
+
+    private void removeConnectionToService() {
+        RcsFeatureManager manager = getFeatureManager();
+        if (manager != null) {
+            manager.unregisterImsRegistrationCallback(
+                    mImsRcsRegistrationHelper.getCallbackBinder());
+            // Remove persistent listener connection.
+            manager.releaseConnection();
+        }
+        mImsRcsRegistrationHelper.reset();
+    }
+
+    private void updateConnectionStatus(RcsFeatureManager manager) {
+        synchronized (mLock) {
+            mFeatureManager = manager;
+            if (mFeatureManager != null) {
+                for (Feature c : mFeatures.values()) {
+                    c.onRcsConnected(manager);
+                }
+            } else {
+                for (Feature c : mFeatures.values()) {
+                    c.onRcsDisconnected();
+                }
+            }
+        }
+    }
+
+    private RcsFeatureManager getFeatureManager() {
+        synchronized (mLock) {
+            return mFeatureManager;
+        }
+    }
+
+    /**
+     * Dump this controller's instance information for usage in dumpsys.
+     */
+    public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
+        IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
+        pw.print("slotId=");
+        pw.println(mSlotId);
+        pw.print("RegistrationState=");
+        pw.println(mImsRcsRegistrationHelper.getImsRegistrationState());
+        pw.print("connected=");
+        synchronized (mLock) {
+            pw.println(mFeatureManager != null);
+        }
+    }
+
+    private void logw(String log) {
+        Log.w(LOG_TAG, getLogPrefix().append(log).toString());
+    }
+
+    private StringBuilder getLogPrefix() {
+        StringBuilder sb = new StringBuilder("[");
+        sb.append(mSlotId);
+        sb.append("] ");
+        return sb;
+    }
+}
diff --git a/src/com/android/services/telephony/rcs/TelephonyRcsService.java b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
new file mode 100644
index 0000000..c85e9a9
--- /dev/null
+++ b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2020 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.rcs;
+
+import android.annotation.AnyThread;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.AsyncResult;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.PhoneConfigurationManager;
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Singleton service setup to manage RCS related services that the platform provides such as User
+ * Capability Exchange.
+ */
+@AnyThread
+public class TelephonyRcsService {
+
+    private static final String LOG_TAG = "TelephonyRcsService";
+
+    /**
+     * Used to inject RcsFeatureController and UserCapabilityExchangeImpl instances for testing.
+     */
+    @VisibleForTesting
+    public interface FeatureFactory {
+        /**
+         * @return an {@link RcsFeatureController} assoicated with the slot specified.
+         */
+        RcsFeatureController createController(Context context, int slotId);
+
+        /**
+         * @return an instance of {@link UserCapabilityExchangeImpl} associated with the slot
+         * specified.
+         */
+        UserCapabilityExchangeImpl createUserCapabilityExchange(Context context, int slotId,
+                int subId);
+    }
+
+    private FeatureFactory mFeatureFactory = new FeatureFactory() {
+        @Override
+        public RcsFeatureController createController(Context context, int slotId) {
+            return new RcsFeatureController(context, slotId);
+        }
+
+        @Override
+        public UserCapabilityExchangeImpl createUserCapabilityExchange(Context context, int slotId,
+                int subId) {
+            return new UserCapabilityExchangeImpl(context, slotId, subId);
+        }
+    };
+
+    // Notifies this service that there has been a change in available slots.
+    private static final int HANDLER_MSIM_CONFIGURATION_CHANGE = 1;
+
+    private final Context mContext;
+    private final Object mLock = new Object();
+    private int mNumSlots;
+
+    // Maps slot ID -> RcsFeatureController.
+    private SparseArray<RcsFeatureController> mFeatureControllers;
+
+    private BroadcastReceiver mCarrierConfigChangedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent == null) {
+                return;
+            }
+            if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) {
+                Bundle bundle = intent.getExtras();
+                if (bundle == null) {
+                    return;
+                }
+                int slotId = bundle.getInt(CarrierConfigManager.EXTRA_SLOT_INDEX,
+                        SubscriptionManager.INVALID_PHONE_INDEX);
+                int subId = bundle.getInt(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX,
+                        SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+                updateFeatureControllerSubscription(slotId, subId);
+            }
+        }
+    };
+
+    private Handler mHandler = new Handler(Looper.getMainLooper(), (msg) -> {
+        switch (msg.what) {
+            case HANDLER_MSIM_CONFIGURATION_CHANGE: {
+                AsyncResult result = (AsyncResult) msg.obj;
+                Integer numSlots = (Integer) result.result;
+                if (numSlots == null) {
+                    Log.w(LOG_TAG, "msim config change with null num slots.");
+                    break;
+                }
+                updateFeatureControllerSize(numSlots);
+                break;
+            }
+            default:
+                return false;
+        }
+        return true;
+    });
+
+    public TelephonyRcsService(Context context, int numSlots) {
+        mContext = context;
+        mNumSlots = numSlots;
+        mFeatureControllers = new SparseArray<>(numSlots);
+    }
+
+    /**
+     * @return the {@link RcsFeatureController} associated with the given slot.
+     */
+    public RcsFeatureController getFeatureController(int slotId) {
+        synchronized (mLock) {
+            return mFeatureControllers.get(slotId);
+        }
+    }
+
+    /**
+     * Called after instance creation to initialize internal structures as well as register for
+     * system callbacks.
+     */
+    public void initialize() {
+        updateFeatureControllerSize(mNumSlots);
+
+        PhoneConfigurationManager.registerForMultiSimConfigChange(mHandler,
+                HANDLER_MSIM_CONFIGURATION_CHANGE, null);
+        mContext.registerReceiver(mCarrierConfigChangedReceiver, new IntentFilter(
+                CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
+    }
+
+    @VisibleForTesting
+    public void setFeatureFactory(FeatureFactory f) {
+        mFeatureFactory = f;
+    }
+
+    /**
+     * Update the number of {@link RcsFeatureController}s that are created based on the number of
+     * active slots on the device.
+     */
+    @VisibleForTesting
+    public void updateFeatureControllerSize(int newNumSlots) {
+        synchronized (mLock) {
+            int oldNumSlots = mFeatureControllers.size();
+            if (oldNumSlots == newNumSlots) {
+                return;
+            }
+            Log.i(LOG_TAG, "updateFeatureControllers: oldSlots=" + oldNumSlots + ", newNumSlots="
+                    + newNumSlots);
+            mNumSlots = newNumSlots;
+            if (oldNumSlots < newNumSlots) {
+                for (int i = oldNumSlots; i < newNumSlots; i++) {
+                    RcsFeatureController c = constructFeatureController(i);
+                    // Do not add feature controllers for inactive subscriptions
+                    if (c.hasActiveFeatures()) {
+                        mFeatureControllers.put(i, c);
+                    }
+                }
+            } else {
+                for (int i = (oldNumSlots - 1); i > (newNumSlots - 1); i--) {
+                    RcsFeatureController c = mFeatureControllers.get(i);
+                    if (c != null) {
+                        mFeatureControllers.remove(i);
+                        c.destroy();
+                    }
+                }
+            }
+        }
+    }
+
+    private void updateFeatureControllerSubscription(int slotId, int newSubId) {
+        synchronized (mLock) {
+            RcsFeatureController f = mFeatureControllers.get(slotId);
+            Log.i(LOG_TAG, "updateFeatureControllerSubscription: slotId=" + slotId + " newSubId="
+                    + newSubId + ", existing feature=" + (f != null));
+            if (SubscriptionManager.isValidSubscriptionId(newSubId)) {
+                if (f == null) {
+                    // A controller doesn't exist for this slot yet.
+                    f = mFeatureFactory.createController(mContext, slotId);
+                    updateSupportedFeatures(f, slotId, newSubId);
+                    if (f.hasActiveFeatures()) mFeatureControllers.put(slotId, f);
+                } else {
+                    updateSupportedFeatures(f, slotId, newSubId);
+                    // Do not keep an empty container around.
+                    if (!f.hasActiveFeatures()) {
+                        f.destroy();
+                        mFeatureControllers.remove(slotId);
+                    }
+                }
+            }
+            if (f != null) f.updateAssociatedSubscription(newSubId);
+        }
+    }
+
+    private RcsFeatureController constructFeatureController(int slotId) {
+        RcsFeatureController c = mFeatureFactory.createController(mContext, slotId);
+        int subId = getSubscriptionFromSlot(slotId);
+        updateSupportedFeatures(c, slotId, subId);
+        return c;
+    }
+
+    private void updateSupportedFeatures(RcsFeatureController c, int slotId, int subId) {
+        if (doesSubscriptionSupportPresence(subId)) {
+            if (c.getFeature(UserCapabilityExchangeImpl.class) == null) {
+                c.addFeature(mFeatureFactory.createUserCapabilityExchange(mContext, slotId, subId),
+                        UserCapabilityExchangeImpl.class);
+            }
+        } else {
+            if (c.getFeature(UserCapabilityExchangeImpl.class) != null) {
+                c.removeFeature(UserCapabilityExchangeImpl.class);
+            }
+        }
+        // Only start the connection procedure if we have active features.
+        if (c.hasActiveFeatures()) c.connect();
+    }
+
+    private boolean doesSubscriptionSupportPresence(int subId) {
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) return false;
+        CarrierConfigManager carrierConfigManager =
+                mContext.getSystemService(CarrierConfigManager.class);
+        if (carrierConfigManager == null) return false;
+        boolean supportsUce = carrierConfigManager.getConfigForSubId(subId).getBoolean(
+                CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL);
+        supportsUce |= carrierConfigManager.getConfigForSubId(subId).getBoolean(
+                CarrierConfigManager.KEY_USE_RCS_SIP_OPTIONS_BOOL);
+        return supportsUce;
+    }
+
+
+    private int getSubscriptionFromSlot(int slotId) {
+        SubscriptionManager manager = mContext.getSystemService(SubscriptionManager.class);
+        if (manager == null) {
+            Log.w(LOG_TAG, "Couldn't find SubscriptionManager for slotId=" + slotId);
+            return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+        }
+        int[] subIds = manager.getSubscriptionIds(slotId);
+        if (subIds != null && subIds.length > 0) {
+            return subIds[0];
+        }
+        return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+    }
+
+    /**
+     * Dump this instance into a readable format for dumpsys usage.
+     */
+    public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
+        IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
+        pw.println("RcsFeatureControllers:");
+        pw.increaseIndent();
+        synchronized (mLock) {
+            for (int i = 0; i < mNumSlots; i++) {
+                RcsFeatureController f = mFeatureControllers.get(i);
+                pw.increaseIndent();
+                f.dump(fd, printWriter, args);
+                pw.decreaseIndent();
+            }
+        }
+        pw.decreaseIndent();
+    }
+}
diff --git a/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java b/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java
new file mode 100644
index 0000000..ac8f9bf
--- /dev/null
+++ b/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2020 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.rcs;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.telephony.ims.RcsContactUceCapability;
+import android.telephony.ims.RcsUceAdapter;
+import android.telephony.ims.aidl.IRcsUceControllerCallback;
+import android.util.Log;
+
+import com.android.ims.RcsFeatureManager;
+import com.android.ims.ResultCode;
+import com.android.phone.R;
+import com.android.service.ims.presence.ContactCapabilityResponse;
+import com.android.service.ims.presence.PresenceBase;
+import com.android.service.ims.presence.PresencePublication;
+import com.android.service.ims.presence.PresencePublisher;
+import com.android.service.ims.presence.PresenceSubscriber;
+import com.android.service.ims.presence.SubscribePublisher;
+
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+/**
+ * Implements User Capability Exchange using Presence.
+ */
+public class UserCapabilityExchangeImpl implements RcsFeatureController.Feature, SubscribePublisher,
+        PresencePublisher {
+
+    private static final String LOG_TAG = "RcsUceImpl";
+
+    private int mSlotId;
+    private int mSubId;
+
+    private final PresencePublication mPresencePublication;
+    private final PresenceSubscriber mPresenceSubscriber;
+
+    private final ConcurrentHashMap<Integer, IRcsUceControllerCallback> mPendingCapabilityRequests =
+            new ConcurrentHashMap<>();
+
+    UserCapabilityExchangeImpl(Context context, int slotId, int subId) {
+        mSlotId = slotId;
+        mSubId = subId;
+        logi("created");
+
+        String[] volteError = context.getResources().getStringArray(
+                R.array.config_volte_provision_error_on_publish_response);
+        String[] rcsError = context.getResources().getStringArray(
+                R.array.config_rcs_provision_error_on_publish_response);
+
+        // Initialize PresencePublication
+        mPresencePublication = new PresencePublication(null /*PresencePublisher*/, context,
+                volteError, rcsError);
+        // Initialize PresenceSubscriber
+        mPresenceSubscriber = new PresenceSubscriber(null /*SubscribePublisher*/, context,
+                volteError, rcsError);
+
+        onAssociatedSubscriptionUpdated(mSubId);
+    }
+
+
+    // Runs on main thread.
+    @Override
+    public void onRcsConnected(RcsFeatureManager rcsFeatureManager) {
+        logi("onRcsConnected");
+        mPresencePublication.updatePresencePublisher(this);
+        mPresenceSubscriber.updatePresenceSubscriber(this);
+    }
+
+    // Runs on main thread.
+    @Override
+    public void onRcsDisconnected() {
+        logi("onRcsDisconnected");
+        mPresencePublication.removePresencePublisher();
+        mPresenceSubscriber.removePresenceSubscriber();
+    }
+
+    // Runs on main thread.
+    @Override
+    public void onAssociatedSubscriptionUpdated(int subId) {
+        mPresencePublication.handleAssociatedSubscriptionChanged(subId);
+        mPresenceSubscriber.handleAssociatedSubscriptionChanged(subId);
+    }
+
+    /**
+     * Should be called before destroying this instance.
+     * This instance is not usable after this method is called.
+     */
+    // Called on main thread.
+    public void onDestroy() {
+        onRcsDisconnected();
+    }
+
+    /**
+     * @return the UCE Publish state.
+     */
+    // May happen on a Binder thread, PresencePublication locks to get result.
+    public int getUcePublishState() {
+        int publishState = mPresencePublication.getPublishState();
+        return toUcePublishState(publishState);
+    }
+
+    /**
+     * Perform a capabilities request and call {@link IRcsUceControllerCallback} with the result.
+     */
+    // May happen on a Binder thread, PresenceSubscriber locks when requesting Capabilities.
+    public void requestCapabilities(List<Uri> contactNumbers, IRcsUceControllerCallback c) {
+        List<String> numbers = contactNumbers.stream()
+                .map(UserCapabilityExchangeImpl::getNumberFromUri).collect(Collectors.toList());
+        int taskId = mPresenceSubscriber.requestCapability(numbers,
+                new ContactCapabilityResponse() {
+                    @Override
+                    public void onSuccess(int reqId) {
+                        logi("onSuccess called for reqId:" + reqId);
+                    }
+
+                    @Override
+                    public void onError(int reqId, int resultCode) {
+                        IRcsUceControllerCallback c = mPendingCapabilityRequests.remove(reqId);
+                        try {
+                            if (c != null) {
+                                c.onError(toUceError(resultCode));
+                            } else {
+                                logw("onError called for unknown reqId:" + reqId);
+                            }
+                        } catch (RemoteException e) {
+                            logi("Calling back to dead service");
+                        }
+                    }
+
+                    @Override
+                    public void onFinish(int reqId) {
+                        logi("onFinish called for reqId:" + reqId);
+                    }
+
+                    @Override
+                    public void onTimeout(int reqId) {
+                        IRcsUceControllerCallback c = mPendingCapabilityRequests.remove(reqId);
+                        try {
+                            if (c != null) {
+                                c.onError(RcsUceAdapter.ERROR_REQUEST_TIMEOUT);
+                            } else {
+                                logw("onTimeout called for unknown reqId:" + reqId);
+                            }
+                        } catch (RemoteException e) {
+                            logi("Calling back to dead service");
+                        }
+                    }
+
+                    @Override
+                    public void onCapabilitiesUpdated(int reqId,
+                            List<RcsContactUceCapability> contactCapabilities,
+                            boolean updateLastTimestamp) {
+                        IRcsUceControllerCallback c = mPendingCapabilityRequests.remove(reqId);
+                        try {
+                            if (c != null) {
+                                c.onCapabilitiesReceived(contactCapabilities);
+                            } else {
+                                logw("onCapabilitiesUpdated, unknown reqId:" + reqId);
+                            }
+                        } catch (RemoteException e) {
+                            logw("onCapabilitiesUpdated on dead service");
+                        }
+                    }
+                });
+        if (taskId < 0) {
+            try {
+                c.onError(toUceError(taskId));
+                return;
+            } catch (RemoteException e) {
+                logi("Calling back to dead service");
+            }
+        }
+        mPendingCapabilityRequests.put(taskId, c);
+    }
+
+    @Override
+    public int getPublisherState() {
+        return 0;
+    }
+
+    @Override
+    public int requestPublication(RcsContactUceCapability capabilities, String contactUri,
+            int taskId) {
+        return 0;
+    }
+
+    @Override
+    public int requestCapability(String[] formatedContacts, int taskId) {
+        return 0;
+    }
+
+    @Override
+    public int requestAvailability(String formattedContact, int taskId) {
+        return 0;
+    }
+
+    @Override
+    public int getStackStatusForCapabilityRequest() {
+        return 0;
+    }
+
+    @Override
+    public void updatePublisherState(int publishState) {
+
+    }
+
+    private static String getNumberFromUri(Uri uri) {
+        String number = uri.getSchemeSpecificPart();
+        String[] numberParts = number.split("[@;:]");
+
+        if (numberParts.length == 0) {
+            return null;
+        }
+        return numberParts[0];
+    }
+
+    private static int toUcePublishState(int publishState) {
+        switch (publishState) {
+            case PresenceBase.PUBLISH_STATE_200_OK:
+                return RcsUceAdapter.PUBLISH_STATE_OK;
+            case PresenceBase.PUBLISH_STATE_NOT_PUBLISHED:
+                return RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED;
+            case PresenceBase.PUBLISH_STATE_VOLTE_PROVISION_ERROR:
+                return RcsUceAdapter.PUBLISH_STATE_VOLTE_PROVISION_ERROR;
+            case PresenceBase.PUBLISH_STATE_RCS_PROVISION_ERROR:
+                return RcsUceAdapter.PUBLISH_STATE_RCS_PROVISION_ERROR;
+            case PresenceBase.PUBLISH_STATE_REQUEST_TIMEOUT:
+                return RcsUceAdapter.PUBLISH_STATE_REQUEST_TIMEOUT;
+            case PresenceBase.PUBLISH_STATE_OTHER_ERROR:
+                return RcsUceAdapter.PUBLISH_STATE_OTHER_ERROR;
+            default:
+                return RcsUceAdapter.PUBLISH_STATE_OTHER_ERROR;
+        }
+    }
+
+    private static int toUceError(int resultCode) {
+        switch (resultCode) {
+            case ResultCode.SUBSCRIBE_NOT_REGISTERED:
+                return RcsUceAdapter.ERROR_NOT_REGISTERED;
+            case ResultCode.SUBSCRIBE_REQUEST_TIMEOUT:
+                return RcsUceAdapter.ERROR_REQUEST_TIMEOUT;
+            case ResultCode.SUBSCRIBE_FORBIDDEN:
+                return RcsUceAdapter.ERROR_FORBIDDEN;
+            case ResultCode.SUBSCRIBE_NOT_FOUND:
+                return RcsUceAdapter.ERROR_NOT_FOUND;
+            case ResultCode.SUBSCRIBE_TOO_LARGE:
+                return RcsUceAdapter.ERROR_REQUEST_TOO_LARGE;
+            case ResultCode.SUBSCRIBE_INSUFFICIENT_MEMORY:
+                return RcsUceAdapter.ERROR_INSUFFICIENT_MEMORY;
+            case ResultCode.SUBSCRIBE_LOST_NETWORK:
+                return RcsUceAdapter.ERROR_LOST_NETWORK;
+            case ResultCode.SUBSCRIBE_ALREADY_IN_QUEUE:
+                return RcsUceAdapter.ERROR_ALREADY_IN_QUEUE;
+            default:
+                return RcsUceAdapter.ERROR_GENERIC_FAILURE;
+        }
+    }
+
+    private void logi(String log) {
+        Log.i(LOG_TAG, getLogPrefix().append(log).toString());
+    }
+
+    private void logw(String log) {
+        Log.w(LOG_TAG, getLogPrefix().append(log).toString());
+    }
+
+    private StringBuilder getLogPrefix() {
+        StringBuilder builder = new StringBuilder("[");
+        builder.append(mSlotId);
+        builder.append("->");
+        builder.append(mSubId);
+        builder.append("] ");
+        return builder;
+    }
+}
diff --git a/testapps/Android.mk b/testapps/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/testapps/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/testapps/EmbmsServiceTestApp/Android.bp b/testapps/EmbmsServiceTestApp/Android.bp
new file mode 100644
index 0000000..e4a54cb
--- /dev/null
+++ b/testapps/EmbmsServiceTestApp/Android.bp
@@ -0,0 +1,11 @@
+// Build the Sample Embms Services
+android_app {
+    name: "EmbmsTestService",
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    certificate: "platform",
+    privileged: true,
+    // Uncomment the following line to build the EmbmsTestService
+    // into the userdebug build:
+    // LOCAL_MODULE_TAGS := debug
+}
diff --git a/testapps/EmbmsServiceTestApp/Android.mk b/testapps/EmbmsServiceTestApp/Android.mk
deleted file mode 100644
index 29b8112..0000000
--- a/testapps/EmbmsServiceTestApp/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# Build the Sample Embms Services
-include $(CLEAR_VARS)
-
-src_dirs := src
-res_dirs := res
-
-LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
-LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
-
-LOCAL_PACKAGE_NAME := EmbmsTestService
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
-# Uncomment the following line to build the EmbmsTestService into the userdebug build.
-# LOCAL_MODULE_TAGS := debug
-
-include $(BUILD_PACKAGE)
diff --git a/testapps/EmbmsTestDownloadApp/Android.bp b/testapps/EmbmsTestDownloadApp/Android.bp
new file mode 100644
index 0000000..63f4e83
--- /dev/null
+++ b/testapps/EmbmsTestDownloadApp/Android.bp
@@ -0,0 +1,12 @@
+src_dirs = ["src"]
+res_dirs = ["res"]
+android_test {
+    name: "EmbmsTestDownloadApp",
+    static_libs: [
+        "androidx.recyclerview_recyclerview",
+        "androidx.legacy_legacy-support-v4",
+    ],
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    certificate: "platform",
+}
diff --git a/testapps/EmbmsTestDownloadApp/Android.mk b/testapps/EmbmsTestDownloadApp/Android.mk
deleted file mode 100644
index bd53d79..0000000
--- a/testapps/EmbmsTestDownloadApp/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# Build the Sample Embms Download frontend
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-        androidx.recyclerview_recyclerview \
-        androidx.legacy_legacy-support-v4
-
-src_dirs := src
-res_dirs := res
-
-LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
-LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
-
-LOCAL_PACKAGE_NAME := EmbmsTestDownloadApp
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_PACKAGE)
diff --git a/testapps/EmbmsTestStreamingApp/Android.bp b/testapps/EmbmsTestStreamingApp/Android.bp
new file mode 100644
index 0000000..814c5ca
--- /dev/null
+++ b/testapps/EmbmsTestStreamingApp/Android.bp
@@ -0,0 +1,7 @@
+android_test {
+    name: "EmbmsTestStreamingApp",
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    certificate: "platform",
+    //LOCAL_MODULE_TAGS := debug
+}
diff --git a/testapps/EmbmsTestStreamingApp/Android.mk b/testapps/EmbmsTestStreamingApp/Android.mk
deleted file mode 100644
index f574990..0000000
--- a/testapps/EmbmsTestStreamingApp/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# Build the Sample Embms Streaming frontend
-include $(CLEAR_VARS)
-
-src_dirs := src
-res_dirs := res
-
-LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
-LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
-
-LOCAL_PACKAGE_NAME := EmbmsTestStreamingApp
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-LOCAL_MODULE_TAGS := tests
-#LOCAL_MODULE_TAGS := debug
-
-include $(BUILD_PACKAGE)
diff --git a/testapps/ImsTestService/Android.bp b/testapps/ImsTestService/Android.bp
new file mode 100644
index 0000000..a0b4edb
--- /dev/null
+++ b/testapps/ImsTestService/Android.bp
@@ -0,0 +1,13 @@
+android_app {
+    name: "ImsTestApp",
+    static_libs: [
+        "androidx.legacy_legacy-support-v4",
+        "androidx.appcompat_appcompat",
+        "androidx.recyclerview_recyclerview",
+        "androidx.cardview_cardview",
+    ],
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    certificate: "platform",
+    privileged: true,
+}
diff --git a/testapps/ImsTestService/Android.mk b/testapps/ImsTestService/Android.mk
deleted file mode 100644
index 2869c86..0000000
--- a/testapps/ImsTestService/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-    androidx.legacy_legacy-support-v4 \
-    androidx.appcompat_appcompat \
-    androidx.recyclerview_recyclerview \
-    androidx.cardview_cardview
-
-LOCAL_USE_AAPT2 := true
-
-src_dirs := src
-res_dirs := res
-
-LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
-LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
-
-LOCAL_PACKAGE_NAME := ImsTestApp
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
-
-include $(BUILD_PACKAGE)
diff --git a/testapps/SmsManagerTestApp/Android.bp b/testapps/SmsManagerTestApp/Android.bp
new file mode 100644
index 0000000..5333eab
--- /dev/null
+++ b/testapps/SmsManagerTestApp/Android.bp
@@ -0,0 +1,5 @@
+android_app {
+    name: "SmsManagerTestApp",
+    srcs: ["src/**/*.java"],
+    sdk_version: "current",
+}
diff --git a/testapps/SmsManagerTestApp/Android.mk b/testapps/SmsManagerTestApp/Android.mk
deleted file mode 100644
index 307366b..0000000
--- a/testapps/SmsManagerTestApp/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-src_dirs := src
-res_dirs := res
-
-LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
-LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
-
-LOCAL_PACKAGE_NAME := SmsManagerTestApp
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
diff --git a/testapps/TelephonyManagerTestApp/Android.bp b/testapps/TelephonyManagerTestApp/Android.bp
new file mode 100644
index 0000000..8a37c99
--- /dev/null
+++ b/testapps/TelephonyManagerTestApp/Android.bp
@@ -0,0 +1,7 @@
+android_test {
+    name: "TelephonyManagerTestApp",
+    srcs: ["src/**/*.java"],
+    javacflags: ["-parameters"],
+    platform_apis: true,
+    certificate: "platform",
+}
diff --git a/testapps/TelephonyManagerTestApp/Android.mk b/testapps/TelephonyManagerTestApp/Android.mk
deleted file mode 100644
index 290b261..0000000
--- a/testapps/TelephonyManagerTestApp/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-src_dirs := src
-res_dirs := res
-
-LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
-LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
-
-LOCAL_JAVACFLAGS := -parameters
-
-LOCAL_PACKAGE_NAME := TelephonyManagerTestApp
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_PACKAGE)
diff --git a/testapps/TelephonyManagerTestApp/src/com/android/phone/testapps/telephonymanagertestapp/ParameterParser.java b/testapps/TelephonyManagerTestApp/src/com/android/phone/testapps/telephonymanagertestapp/ParameterParser.java
index 097c90a..ccb5639 100644
--- a/testapps/TelephonyManagerTestApp/src/com/android/phone/testapps/telephonymanagertestapp/ParameterParser.java
+++ b/testapps/TelephonyManagerTestApp/src/com/android/phone/testapps/telephonymanagertestapp/ParameterParser.java
@@ -19,12 +19,19 @@
 import android.content.Context;
 import android.telephony.NumberVerificationCallback;
 import android.telephony.PhoneNumberRange;
+import android.telephony.RadioAccessSpecifier;
+import android.text.TextUtils;
 import android.widget.Toast;
 
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 import java.util.function.Function;
+import java.util.stream.Collectors;
 
 class ParameterParser {
     private static ParameterParser sInstance;
@@ -42,6 +49,9 @@
                 put(PhoneNumberRange.class, ParameterParser::parsePhoneNumberRange);
                 put(Executor.class, s -> parseExecutor(s));
                 put(NumberVerificationCallback.class, s -> parseNumberVerificationCallback(s));
+                put(Consumer.class, s -> parseConsumer(s));
+                put(List.class, s -> parseList(s));
+                put(RadioAccessSpecifier.class, s -> parseRadioAccessSpecifier(s));
             }};
 
     private ParameterParser(Context context) {
@@ -49,6 +59,7 @@
     }
 
     Object executeParser(Class type, String input) {
+        if ("null".equals(input)) return null;
         return mParsers.getOrDefault(type, s -> null).apply(input);
     }
 
@@ -64,6 +75,57 @@
         return mContext.getMainExecutor();
     }
 
+    private Consumer parseConsumer(String input) {
+        return o -> Toast.makeText(mContext, "Consumer: " + String.valueOf(o), Toast.LENGTH_SHORT)
+                .show();
+    }
+
+    /**
+     * input format: (ran)/(band1)+(band2)+.../(chan1)+(chan2)+...
+     * @return
+     */
+    private RadioAccessSpecifier parseRadioAccessSpecifier(String input) {
+        String[] parts = input.split("/");
+        int ran = Integer.parseInt(parts[0]);
+        String[] bandStrings = parts[1].split("\\+");
+        int[] bands = new int[bandStrings.length];
+        String[] chanStrings = parts[2].split("\\+");
+        int[] chans = new int[chanStrings.length];
+
+        for (int i = 0; i < bands.length; i++) {
+            bands[i] = Integer.parseInt(bandStrings[i]);
+        }
+
+        for (int i = 0; i < chans.length; i++) {
+            chans[i] = Integer.parseInt(chanStrings[i]);
+        }
+        return new RadioAccessSpecifier(ran, bands, chans);
+    }
+
+    private List parseList(String input) {
+        if (TextUtils.isEmpty(input)) {
+            return Collections.emptyList();
+        }
+        String[] components = input.split(" ");
+        String className = components[0];
+        Class c;
+        try {
+            c = mContext.getClassLoader().loadClass(className);
+        } catch (ClassNotFoundException e) {
+            Toast.makeText(mContext, "Invalid class " + className,
+                    Toast.LENGTH_SHORT).show();
+            return null;
+        }
+        if (!mParsers.containsKey(c)) {
+            Toast.makeText(mContext, "Cannot parse " + className,
+                    Toast.LENGTH_SHORT).show();
+            return null;
+        }
+        return Arrays.stream(components).skip(1)
+                .map(mParsers.get(c))
+                .collect(Collectors.toList());
+    }
+
     private NumberVerificationCallback parseNumberVerificationCallback(String input) {
         return new NumberVerificationCallback() {
             @Override
diff --git a/testapps/TelephonyRegistryTestApp/Android.bp b/testapps/TelephonyRegistryTestApp/Android.bp
new file mode 100644
index 0000000..fec5286
--- /dev/null
+++ b/testapps/TelephonyRegistryTestApp/Android.bp
@@ -0,0 +1,7 @@
+android_test {
+    name: "TelephonyRegistryTestApp",
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    certificate: "platform",
+    //LOCAL_MODULE_TAGS := debug
+}
diff --git a/testapps/TelephonyRegistryTestApp/Android.mk b/testapps/TelephonyRegistryTestApp/Android.mk
deleted file mode 100644
index 8c0d286..0000000
--- a/testapps/TelephonyRegistryTestApp/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-src_dirs := src
-res_dirs := res
-
-LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
-LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
-
-LOCAL_PACKAGE_NAME := TelephonyRegistryTestApp
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-LOCAL_MODULE_TAGS := tests
-#LOCAL_MODULE_TAGS := debug
-
-include $(BUILD_PACKAGE)
diff --git a/tests/Android.bp b/tests/Android.bp
index 22b40b5..7ed234e 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -25,6 +25,7 @@
         "telephony-common",
         "android.test.base",
         "ims-common",
+        "android.test.mock",
     ],
     platform_apis: true,
     certificate: "platform",
diff --git a/tests/src/com/android/TelephonyTestBase.java b/tests/src/com/android/TelephonyTestBase.java
index 01267d8..86c5402 100644
--- a/tests/src/com/android/TelephonyTestBase.java
+++ b/tests/src/com/android/TelephonyTestBase.java
@@ -16,6 +16,8 @@
 
 package com.android;
 
+import static org.mockito.Mockito.spy;
+
 import android.os.Handler;
 import android.os.Looper;
 import android.util.Log;
@@ -34,7 +36,7 @@
 
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mContext = new TestContext();
+        mContext = spy(new TestContext());
         // Set up the looper if it does not exist on the test thread.
         if (Looper.myLooper() == null) {
             Looper.prepare();
diff --git a/tests/src/com/android/TestContext.java b/tests/src/com/android/TestContext.java
index 776ec6a..c190be9 100644
--- a/tests/src/com/android/TestContext.java
+++ b/tests/src/com/android/TestContext.java
@@ -34,6 +34,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.concurrent.Executor;
+
 public class TestContext extends MockContext {
 
     @Mock CarrierConfigManager mMockCarrierConfigManager;
@@ -49,6 +51,12 @@
     }
 
     @Override
+    public Executor getMainExecutor() {
+        // Just run on current thread
+        return Runnable::run;
+    }
+
+    @Override
     public Context getApplicationContext() {
         return this;
     }
diff --git a/tests/src/com/android/phone/NumberVerificationManagerTest.java b/tests/src/com/android/phone/NumberVerificationManagerTest.java
index d476ba5..f7914ab 100644
--- a/tests/src/com/android/phone/NumberVerificationManagerTest.java
+++ b/tests/src/com/android/phone/NumberVerificationManagerTest.java
@@ -57,7 +57,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         ServiceState ss = mock(ServiceState.class);
-        when(ss.getVoiceRegState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+        when(ss.getState()).thenReturn(ServiceState.STATE_IN_SERVICE);
         when(mPhone1.getServiceState()).thenReturn(ss);
         when(mPhone1.getForegroundCall()).thenReturn(mForegroundCall);
         when(mPhone1.getRingingCall()).thenReturn(mRingingCall);
@@ -107,7 +107,7 @@
     @Test
     public void testNoPhoneInServiceFailure() throws Exception {
         ServiceState ss = mock(ServiceState.class);
-        when(ss.getVoiceRegState()).thenReturn(ServiceState.STATE_POWER_OFF);
+        when(ss.getState()).thenReturn(ServiceState.STATE_POWER_OFF);
         when(mPhone1.getServiceState()).thenReturn(ss);
         when(mPhone2.getServiceState()).thenReturn(ss);
         NumberVerificationManager manager =
@@ -138,7 +138,7 @@
     @Test
     public void testVerificationWorksWithOnePhoneInService() throws Exception {
         ServiceState ss = mock(ServiceState.class);
-        when(ss.getVoiceRegState()).thenReturn(ServiceState.STATE_POWER_OFF);
+        when(ss.getState()).thenReturn(ServiceState.STATE_POWER_OFF);
         when(mPhone1.getServiceState()).thenReturn(ss);
         NumberVerificationManager manager =
                 new NumberVerificationManager(() -> new Phone[]{mPhone1, mPhone2});
diff --git a/tests/src/com/android/phone/PhoneGlobalsTest.java b/tests/src/com/android/phone/PhoneGlobalsTest.java
new file mode 100644
index 0000000..d45a890
--- /dev/null
+++ b/tests/src/com/android/phone/PhoneGlobalsTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.TelephonyTestBase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+
+@RunWith(AndroidJUnit4.class)
+public class PhoneGlobalsTest extends TelephonyTestBase {
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    @Test
+    public void testGetImsResources() throws Exception {
+        // Do not use test context here, we are testing that overlaying for different locales works
+        // correctly
+        Context realContext = InstrumentationRegistry.getTargetContext();
+        String defaultImsMmtelPackage = getResourcesForLocale(realContext, Locale.US).getString(
+                R.string.config_ims_mmtel_package);
+        String defaultImsMmtelPackageUk = getResourcesForLocale(realContext, Locale.UK).getString(
+                R.string.config_ims_mmtel_package);
+        assertEquals("locales changed IMS package configuration!", defaultImsMmtelPackage,
+                defaultImsMmtelPackageUk);
+    }
+
+    private Resources getResourcesForLocale(Context context, Locale locale) {
+        Configuration config = new Configuration();
+        config.setToDefaults();
+        config.setLocale(locale);
+        Context localeContext = context.createConfigurationContext(config);
+        return localeContext.getResources();
+    }
+}
diff --git a/tests/src/com/android/phone/ServiceStateProviderTest.java b/tests/src/com/android/phone/ServiceStateProviderTest.java
new file mode 100644
index 0000000..574c0c9
--- /dev/null
+++ b/tests/src/com/android/phone/ServiceStateProviderTest.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import static android.provider.Telephony.ServiceStateTable;
+import static android.provider.Telephony.ServiceStateTable.getUriForSubscriptionId;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import android.content.Context;
+import android.content.pm.ProviderInfo;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.telephony.ServiceState;
+import android.telephony.SubscriptionManager;
+import android.test.mock.MockContentResolver;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for simple queries of ServiceStateProvider.
+ *
+ * Build, install and run the tests by running the commands below:
+ *     runtest --path <dir or file>
+ *     runtest --path <dir or file> --test-method <testMethodName>
+ *     e.g.)
+ *         runtest --path tests/src/com/android/phone/ServiceStateProviderTest.java \
+ *                 --test-method testGetServiceState
+ */
+public class ServiceStateProviderTest {
+    private static final String TAG = "ServiceStateProviderTest";
+
+    private Context mContext;
+    private MockContentResolver mContentResolver;
+    private ServiceState mTestServiceState;
+    private ServiceState mTestServiceStateForSubId1;
+
+    private final String[] mTestProjection =
+    {
+        ServiceStateTable.VOICE_REG_STATE,
+        ServiceStateTable.DATA_REG_STATE,
+        ServiceStateTable.VOICE_OPERATOR_ALPHA_LONG,
+        ServiceStateTable.VOICE_OPERATOR_ALPHA_SHORT,
+        ServiceStateTable.VOICE_OPERATOR_NUMERIC,
+        ServiceStateTable.DATA_OPERATOR_ALPHA_LONG,
+        ServiceStateTable.DATA_OPERATOR_ALPHA_SHORT,
+        ServiceStateTable.DATA_OPERATOR_NUMERIC,
+        ServiceStateTable.IS_MANUAL_NETWORK_SELECTION,
+        ServiceStateTable.RIL_VOICE_RADIO_TECHNOLOGY,
+        ServiceStateTable.RIL_DATA_RADIO_TECHNOLOGY,
+        ServiceStateTable.CSS_INDICATOR,
+        ServiceStateTable.NETWORK_ID,
+        ServiceStateTable.SYSTEM_ID,
+        ServiceStateTable.CDMA_ROAMING_INDICATOR,
+        ServiceStateTable.CDMA_DEFAULT_ROAMING_INDICATOR,
+        ServiceStateTable.CDMA_ERI_ICON_INDEX,
+        ServiceStateTable.CDMA_ERI_ICON_MODE,
+        ServiceStateTable.IS_EMERGENCY_ONLY,
+        ServiceStateTable.IS_USING_CARRIER_AGGREGATION,
+        ServiceStateTable.OPERATOR_ALPHA_LONG_RAW,
+        ServiceStateTable.OPERATOR_ALPHA_SHORT_RAW,
+    };
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = mock(Context.class);
+        mContentResolver = new MockContentResolver() {
+            @Override
+            public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
+                throw new RuntimeException("notifyChange!");
+            }
+        };
+        doReturn(mContentResolver).when(mContext).getContentResolver();
+
+        mTestServiceState = new ServiceState();
+        mTestServiceState.setStateOutOfService();
+        mTestServiceStateForSubId1 = new ServiceState();
+        mTestServiceStateForSubId1.setStateOff();
+
+        // Mock out the actual phone state
+        ServiceStateProvider provider = new ServiceStateProvider() {
+            @Override
+            public ServiceState getServiceState(int subId) {
+                if (subId == 1) {
+                    return mTestServiceStateForSubId1;
+                } else {
+                    return mTestServiceState;
+                }
+            }
+
+            @Override
+            public int getDefaultSubId() {
+                return 0;
+            }
+        };
+        ProviderInfo providerInfo = new ProviderInfo();
+        providerInfo.authority = "service-state";
+        provider.attachInfoForTesting(mContext, providerInfo);
+        mContentResolver.addProvider("service-state", provider);
+    }
+
+    @Test
+    @SmallTest
+    public void testQueryServiceStateWithNoSubId() {
+        // Verify that when calling query with no subId in the uri the default ServiceState is
+        // returned.
+        // In this case the subId is set to 0 and the expected service state is
+        // mTestServiceState.
+        verifyServiceStateForSubId(ServiceStateTable.CONTENT_URI, mTestServiceState);
+    }
+
+    @Test
+    @SmallTest
+    public void testGetServiceStateWithDefaultSubId() {
+        // Verify that when calling with the DEFAULT_SUBSCRIPTION_ID the correct ServiceState is
+        // returned
+        // In this case the subId is set to 0 and the expected service state is
+        // mTestServiceState.
+        verifyServiceStateForSubId(
+                getUriForSubscriptionId(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID),
+                mTestServiceState);
+    }
+
+    /**
+     * Test querying the service state for a given subId
+     */
+    @Test
+    @SmallTest
+    public void testGetServiceStateForSubId() {
+        // Verify that when calling with a specific subId the correct ServiceState is returned
+        // In this case the subId is set to 1 and the expected service state is
+        // mTestServiceStateForSubId1
+        verifyServiceStateForSubId(getUriForSubscriptionId(1), mTestServiceStateForSubId1);
+    }
+
+    private void verifyServiceStateForSubId(Uri uri, ServiceState ss) {
+        Cursor cursor = mContentResolver.query(uri, mTestProjection, "",
+                null, null);
+        assertNotNull(cursor);
+        cursor.moveToFirst();
+
+        final int voiceRegState = ss.getState();
+        final int dataRegState = ss.getDataRegistrationState();
+        final String voiceOperatorAlphaLong = ss.getOperatorAlphaLong();
+        final String voiceOperatorAlphaShort = ss.getOperatorAlphaShort();
+        final String voiceOperatorNumeric = ss.getOperatorNumeric();
+        final String dataOperatorAlphaLong = ss.getOperatorAlphaLong();
+        final String dataOperatorAlphaShort = ss.getOperatorAlphaShort();
+        final String dataOperatorNumeric = ss.getOperatorNumeric();
+        final int isManualNetworkSelection = (ss.getIsManualSelection()) ? 1 : 0;
+        final int rilVoiceRadioTechnology = ss.getRilVoiceRadioTechnology();
+        final int rilDataRadioTechnology = ss.getRilDataRadioTechnology();
+        final int cssIndicator = ss.getCssIndicator();
+        final int networkId = ss.getCdmaNetworkId();
+        final int systemId = ss.getCdmaSystemId();
+        final int cdmaRoamingIndicator = ss.getCdmaRoamingIndicator();
+        final int cdmaDefaultRoamingIndicator = ss.getCdmaDefaultRoamingIndicator();
+        final int cdmaEriIconIndex = ss.getCdmaEriIconIndex();
+        final int cdmaEriIconMode = ss.getCdmaEriIconMode();
+        final int isEmergencyOnly = (ss.isEmergencyOnly()) ? 1 : 0;
+        final int isUsingCarrierAggregation = (ss.isUsingCarrierAggregation()) ? 1 : 0;
+        final String operatorAlphaLongRaw = ss.getOperatorAlphaLongRaw();
+        final String operatorAlphaShortRaw = ss.getOperatorAlphaShortRaw();
+
+        assertEquals(voiceRegState, cursor.getInt(0));
+        assertEquals(dataRegState, cursor.getInt(1));
+        assertEquals(voiceOperatorAlphaLong, cursor.getString(2));
+        assertEquals(voiceOperatorAlphaShort, cursor.getString(3));
+        assertEquals(voiceOperatorNumeric, cursor.getString(4));
+        assertEquals(dataOperatorAlphaLong, cursor.getString(5));
+        assertEquals(dataOperatorAlphaShort, cursor.getString(6));
+        assertEquals(dataOperatorNumeric, cursor.getString(7));
+        assertEquals(isManualNetworkSelection, cursor.getInt(8));
+        assertEquals(rilVoiceRadioTechnology, cursor.getInt(9));
+        assertEquals(rilDataRadioTechnology, cursor.getInt(10));
+        assertEquals(cssIndicator, cursor.getInt(11));
+        assertEquals(networkId, cursor.getInt(12));
+        assertEquals(systemId, cursor.getInt(13));
+        assertEquals(cdmaRoamingIndicator, cursor.getInt(14));
+        assertEquals(cdmaDefaultRoamingIndicator, cursor.getInt(15));
+        assertEquals(cdmaEriIconIndex, cursor.getInt(16));
+        assertEquals(cdmaEriIconMode, cursor.getInt(17));
+        assertEquals(isEmergencyOnly, cursor.getInt(18));
+        assertEquals(isUsingCarrierAggregation, cursor.getInt(19));
+        assertEquals(operatorAlphaLongRaw, cursor.getString(20));
+        assertEquals(operatorAlphaShortRaw, cursor.getString(21));
+    }
+
+    /**
+     * Test that we don't notify for certain field changes. (e.g. we don't notify when the NetworkId
+     * or SystemId change) This is an intentional behavior change from the broadcast.
+     */
+    @Test
+    @SmallTest
+    public void testNoNotify() {
+        int subId = 0;
+
+        ServiceState oldSS = new ServiceState();
+        oldSS.setStateOutOfService();
+        oldSS.setCdmaSystemAndNetworkId(1, 1);
+
+        ServiceState newSS = new ServiceState();
+        newSS.setStateOutOfService();
+        newSS.setCdmaSystemAndNetworkId(0, 0);
+
+        // Test that notifyChange is not called for these fields
+        boolean notifyChangeWasCalled = false;
+        try {
+            ServiceStateProvider.notifyChangeForSubIdAndField(mContext, oldSS, newSS, subId);
+        } catch (RuntimeException e) {
+            final String message = e.getMessage();
+            if (message != null &&  message.equals("notifyChange!")) {
+                notifyChangeWasCalled = true;
+            }
+        }
+        assertFalse(notifyChangeWasCalled);
+    }
+
+    @Test
+    @SmallTest
+    public void testNotifyChanged() {
+        int subId = 0;
+
+        ServiceState oldSS = new ServiceState();
+        oldSS.setStateOutOfService();
+        oldSS.setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE);
+
+        ServiceState copyOfOldSS = new ServiceState();
+        copyOfOldSS.setStateOutOfService();
+        copyOfOldSS.setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE);
+
+        ServiceState newSS = new ServiceState();
+        newSS.setStateOutOfService();
+        newSS.setVoiceRegState(ServiceState.STATE_POWER_OFF);
+
+        // Test that notifyChange is not called with no change in notifyChangeForSubIdAndField
+        boolean notifyChangeWasCalled = false;
+        try {
+            ServiceStateProvider.notifyChangeForSubIdAndField(mContext, oldSS, copyOfOldSS, subId);
+        } catch (RuntimeException e) {
+            final String message = e.getMessage();
+            if (message != null &&  message.equals("notifyChange!")) {
+                notifyChangeWasCalled = true;
+            }
+        }
+        assertFalse(notifyChangeWasCalled);
+
+        // Test that notifyChange is not called with no change in notifyChangeForSubId
+        notifyChangeWasCalled = false;
+        try {
+            ServiceStateProvider.notifyChangeForSubId(mContext, oldSS, copyOfOldSS, subId);
+        } catch (RuntimeException e) {
+            final String message = e.getMessage();
+            if (message != null &&  message.equals("notifyChange!")) {
+                notifyChangeWasCalled = true;
+            }
+        }
+        assertFalse(notifyChangeWasCalled);
+
+        // Test that notifyChange is called by notifyChangeForSubIdAndField when the voice_reg_state
+        // changes
+        notifyChangeWasCalled = false;
+        try {
+            ServiceStateProvider.notifyChangeForSubIdAndField(mContext, oldSS, newSS, subId);
+        } catch (RuntimeException e) {
+            final String message = e.getMessage();
+            if (message != null &&  message.equals("notifyChange!")) {
+                notifyChangeWasCalled = true;
+            }
+        }
+        assertTrue(notifyChangeWasCalled);
+
+        // Test that notifyChange is called by notifyChangeForSubId when the voice_reg_state changes
+        notifyChangeWasCalled = false;
+        try {
+            ServiceStateProvider.notifyChangeForSubId(mContext, oldSS, newSS, subId);
+        } catch (RuntimeException e) {
+            final String message = e.getMessage();
+            if (message != null &&  message.equals("notifyChange!")) {
+                notifyChangeWasCalled = true;
+            }
+        }
+        assertTrue(notifyChangeWasCalled);
+    }
+}
diff --git a/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java b/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java
index 8b46bf0..25df848 100644
--- a/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java
+++ b/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java
@@ -34,6 +34,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.TelephonyTestBase;
+import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 
@@ -55,6 +56,7 @@
 
     @Mock Phone mMockPhone;
     @Mock RadioOnStateListener.Callback mCallback;
+    @Mock CommandsInterface mMockCi;
     RadioOnStateListener mListener;
 
     @Override
@@ -67,9 +69,9 @@
     @Override
     @After
     public void tearDown() throws Exception {
+        mListener.getHandler().removeCallbacksAndMessages(null);
         // Wait for the queue to clear...
         waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS /*ms timeout*/);
-        mListener.getHandler().removeCallbacksAndMessages(null);
         mListener = null;
         super.tearDown();
     }
@@ -80,13 +82,17 @@
     @Test
     @SmallTest
     public void testRegisterForCallback() {
-        mListener.waitForRadioOn(mMockPhone, mCallback);
+        mMockPhone.mCi = mMockCi;
+        mListener.waitForRadioOn(mMockPhone, mCallback, false, false);
 
         waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
 
         verify(mMockPhone).unregisterForServiceStateChanged(any(Handler.class));
         verify(mMockPhone).registerForServiceStateChanged(any(Handler.class),
                 eq(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED), isNull());
+
+        verify(mMockCi).registerForOffOrNotAvailable(any(Handler.class),
+                eq(RadioOnStateListener.MSG_RADIO_OFF_OR_NOT_AVAILABLE), isNull());
     }
 
     /**
@@ -99,9 +105,11 @@
     public void testPhoneChangeState_OkToCallTrue() {
         ServiceState state = new ServiceState();
         state.setState(ServiceState.STATE_IN_SERVICE);
+        when(mMockPhone.getServiceState()).thenReturn(state);
         when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
         when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(true);
-        mListener.waitForRadioOn(mMockPhone, mCallback);
+        mMockPhone.mCi = mMockCi;
+        mListener.waitForRadioOn(mMockPhone, mCallback, false, false);
         waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
 
         mListener.getHandler().obtainMessage(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED,
@@ -124,7 +132,8 @@
         when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
         when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(false);
         when(mMockPhone.getServiceState()).thenReturn(state);
-        mListener.waitForRadioOn(mMockPhone, mCallback);
+        mMockPhone.mCi = mMockCi;
+        mListener.waitForRadioOn(mMockPhone, mCallback, false, false);
         waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
 
         mListener.getHandler().obtainMessage(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED,
@@ -152,10 +161,33 @@
         mListener.setMaxNumRetries(2);
 
         // Wait for the timer to expire and check state manually in onRetryTimeout
-        mListener.waitForRadioOn(mMockPhone, mCallback);
+        mMockPhone.mCi = mMockCi;
+        mListener.waitForRadioOn(mMockPhone, mCallback, false, false);
         waitForHandlerActionDelayed(mListener.getHandler(), TIMEOUT_MS, TIMEOUT_MS /*delay*/);
 
         verify(mCallback).onComplete(eq(mListener), eq(false));
-        verify(mMockPhone, times(2)).setRadioPower(eq(true));
+        verify(mMockPhone, times(2)).setRadioPower(eq(true),
+                eq(false), eq(false), eq(false));
+    }
+
+    @Test
+    @SmallTest
+    public void testTimeout_RetryFailure_ForEmergency() {
+        ServiceState state = new ServiceState();
+        state.setState(ServiceState.STATE_POWER_OFF);
+        when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
+        when(mMockPhone.getServiceState()).thenReturn(state);
+        when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(false);
+        mListener.setTimeBetweenRetriesMillis(0/*ms*/);
+        mListener.setMaxNumRetries(2);
+
+        // Wait for the timer to expire and check state manually in onRetryTimeout
+        mMockPhone.mCi = mMockCi;
+        mListener.waitForRadioOn(mMockPhone, mCallback, true, true);
+        waitForHandlerActionDelayed(mListener.getHandler(), TIMEOUT_MS, TIMEOUT_MS /*delay*/);
+
+        verify(mCallback).onComplete(eq(mListener), eq(false));
+        verify(mMockPhone, times(2)).setRadioPower(eq(true),
+                eq(true), eq(true), eq(false));
     }
 }
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index 6e11e51..2060e6f 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -16,7 +16,10 @@
 
 package com.android.services.telephony;
 
+import static com.android.internal.telephony.RILConstants.GSM_PHONE;
+
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.Assert.fail;
@@ -26,6 +29,7 @@
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -58,6 +62,7 @@
 import com.android.internal.telephony.Connection;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneSwitcher;
+import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
 
@@ -93,6 +98,7 @@
     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");
+    private android.telecom.Connection mConnection;
 
     @Mock TelephonyConnectionService.TelephonyManagerProxy mTelephonyManagerProxy;
     @Mock TelephonyConnectionService.SubscriptionManagerProxy mSubscriptionManagerProxy;
@@ -106,6 +112,8 @@
     @Mock Handler mMockHandler;
     @Mock EmergencyNumberTracker mEmergencyNumberTracker;
     @Mock PhoneSwitcher mPhoneSwitcher;
+    @Mock RadioOnHelper mRadioOnHelper;
+    @Mock ServiceStateTracker mSST;
 
     private static class TestTelephonyConnectionService extends TelephonyConnectionService {
 
@@ -135,6 +143,8 @@
         doReturn(false).when(mDeviceState).shouldCheckSimStateBeforeOutgoingCall(any());
         mTestConnectionService.setPhoneSwitcherProxy(mPhoneSwitcherProxy);
         doReturn(mPhoneSwitcher).when(mPhoneSwitcherProxy).getPhoneSwitcher();
+        when(mPhoneNumberUtilsProxy.convertToEmergencyNumber(any(), anyString()))
+                .thenAnswer(invocation -> invocation.getArgument(1));
         mTestConnectionService.setPhoneNumberUtilsProxy(mPhoneNumberUtilsProxy);
         mTestConnectionService.setPhoneUtilsProxy(mPhoneUtilsProxy);
         HandlerThread mockHandlerThread = mock(HandlerThread.class);
@@ -143,6 +153,7 @@
         doReturn(mMockHandler).when(mHandlerFactory).createHandler(any());
         mTestConnectionService.setHandlerFactory(mHandlerFactory);
         mTestConnectionService.setDeviceState(mDeviceState);
+        mTestConnectionService.setRadioOnHelper(mRadioOnHelper);
         doReturn(new DisconnectCause(DisconnectCause.UNKNOWN)).when(mDisconnectCauseFactory)
                 .toTelecomDisconnectCause(anyInt(), any());
         doReturn(new DisconnectCause(DisconnectCause.UNKNOWN)).when(mDisconnectCauseFactory)
@@ -941,6 +952,64 @@
     }
 
     /**
+     * Test that the TelephonyConnectionService successfully turns radio on before placing the
+     * emergency call.
+     */
+    @Test
+    @SmallTest
+    public void testCreateOutgoingEmerge_exitingApm_disconnected() {
+        when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
+        Phone testPhone = setupConnectionServiceInApm();
+
+        ArgumentCaptor<RadioOnStateListener.Callback> callback =
+                ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
+        verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
+                eq(testPhone));
+
+        assertFalse(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
+        when(mSST.isRadioOn()).thenReturn(true);
+        assertTrue(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
+
+        mConnection.setDisconnected(null);
+        callback.getValue().onComplete(null, true);
+        for (Phone phone : mPhoneFactoryProxy.getPhones()) {
+            verify(phone).setRadioPower(true, false, false, true);
+        }
+    }
+
+    /**
+     * Test that the TelephonyConnectionService successfully turns radio on before placing the
+     * emergency call.
+     */
+    @Test
+    @SmallTest
+    public void testCreateOutgoingEmergencyConnection_exitingApm_placeCall() {
+        when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
+        Phone testPhone = setupConnectionServiceInApm();
+
+        ArgumentCaptor<RadioOnStateListener.Callback> callback =
+                ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
+        verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
+                eq(testPhone));
+
+        assertFalse(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
+        when(mSST.isRadioOn()).thenReturn(true);
+        assertTrue(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
+
+        callback.getValue().onComplete(null, true);
+        Runnable delayDialRunnable = verifyRunnablePosted();
+
+        try {
+            doAnswer(invocation -> null).when(mContext).startActivity(any());
+            delayDialRunnable.run();
+            verify(testPhone).dial(anyString(), any());
+        } catch (CallStateException e) {
+            // This shouldn't happen
+            fail();
+        }
+    }
+
+    /**
      * Test that the TelephonyConnectionService does not perform a DDS switch when the carrier
      * supports control-plane fallback.
      */
@@ -1115,9 +1184,49 @@
         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);
+        mConnection = mTestConnectionService.onCreateOutgoingConnection(
+                PHONE_ACCOUNT_HANDLE_1, connectionRequest);
+        assertNotNull("test connection was not set up correctly.", mConnection);
+
+        return testPhone0;
+    }
+
+
+    /**
+     * Set up a mock MSIM device with TEST_ADDRESS set as an emergency number in airplane mode.
+     * @return the Phone associated with slot 0.
+     */
+    private Phone setupConnectionServiceInApm() {
+        ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
+                .setAccountHandle(PHONE_ACCOUNT_HANDLE_1)
+                .setAddress(TEST_ADDRESS)
+                .build();
+        Phone testPhone0 = makeTestPhone(0 /*phoneId*/, ServiceState.STATE_POWER_OFF,
+                false /*isEmergencyOnly*/);
+        Phone testPhone1 = makeTestPhone(1 /*phoneId*/, ServiceState.STATE_POWER_OFF,
+                false /*isEmergencyOnly*/);
+        doReturn(GSM_PHONE).when(testPhone0).getPhoneType();
+        doReturn(GSM_PHONE).when(testPhone1).getPhoneType();
+        List<Phone> phones = new ArrayList<>(2);
+        doReturn(false).when(testPhone0).isRadioOn();
+        doReturn(false).when(testPhone1).isRadioOn();
+        phones.add(testPhone0);
+        phones.add(testPhone1);
+        setPhones(phones);
+        setupHandleToPhoneMap(PHONE_ACCOUNT_HANDLE_1, testPhone0);
+        setupDeviceConfig(testPhone0, testPhone1, 0);
+        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();
+
+        mConnection = mTestConnectionService.onCreateOutgoingConnection(
+                PHONE_ACCOUNT_HANDLE_1, connectionRequest);
+        assertNotNull("test connection was not set up correctly.", mConnection);
 
         return testPhone0;
     }
@@ -1163,6 +1272,7 @@
         when(phone.getPhoneId()).thenReturn(phoneId);
         when(phone.getDefaultPhone()).thenReturn(phone);
         when(phone.getEmergencyNumberTracker()).thenReturn(mEmergencyNumberTracker);
+        when(phone.getServiceStateTracker()).thenReturn(mSST);
         when(mEmergencyNumberTracker.getEmergencyNumber(anyString())).thenReturn(null);
         return phone;
     }
@@ -1193,6 +1303,7 @@
 
     private void setPhones(List<Phone> phones) {
         when(mPhoneFactoryProxy.getPhones()).thenReturn(phones.toArray(new Phone[phones.size()]));
+        when(mPhoneFactoryProxy.getDefaultPhone()).thenReturn(phones.get(0));
     }
 
     private void setPhonesDialConnection(Phone phone, Connection c) {
diff --git a/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java b/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java
new file mode 100644
index 0000000..fbb270d
--- /dev/null
+++ b/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2020 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.rcs;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.telephony.AccessNetworkConstants;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.RegistrationManager;
+import android.telephony.ims.aidl.IImsCapabilityCallback;
+import android.telephony.ims.aidl.IImsRegistrationCallback;
+import android.telephony.ims.feature.RcsFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.TelephonyTestBase;
+import com.android.ims.FeatureConnector;
+import com.android.ims.RcsFeatureManager;
+import com.android.internal.telephony.imsphone.ImsRegistrationCallbackHelper;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+
+import java.util.concurrent.Executor;
+
+@RunWith(AndroidJUnit4.class)
+public class RcsFeatureControllerTest extends TelephonyTestBase {
+
+    private static final ImsReasonInfo REASON_DISCONNECTED = new ImsReasonInfo(
+            ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN, 0, "test");
+
+    @Mock RcsFeatureManager mFeatureManager;
+    @Mock RcsFeatureController.FeatureConnectorFactory<RcsFeatureManager> mFeatureFactory;
+    @Mock ImsRegistrationCallbackHelper.ImsRegistrationUpdate mRegistrationCallback;
+    @Mock FeatureConnector<RcsFeatureManager> mFeatureConnector;
+    @Mock RcsFeatureController.Feature mMockFeature;
+    @Captor ArgumentCaptor<FeatureConnector.Listener<RcsFeatureManager>> mConnectorListener;
+
+    private RcsFeatureController.RegistrationHelperFactory mRegistrationFactory =
+            new RcsFeatureController.RegistrationHelperFactory() {
+                @Override
+                public ImsRegistrationCallbackHelper create(
+                        ImsRegistrationCallbackHelper.ImsRegistrationUpdate cb, Executor executor) {
+                    // Run on current thread for testing.
+                    return new ImsRegistrationCallbackHelper(mRegistrationCallback, Runnable::run);
+                }
+            };
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    @Test
+    public void testRcsFeatureManagerConnectDisconnect() throws Exception {
+        RcsFeatureController controller = createFeatureController();
+        controller.addFeature(mMockFeature, RcsFeatureController.Feature.class);
+        verify(mMockFeature).onRcsDisconnected();
+        // Connect the RcsFeatureManager
+        mConnectorListener.getValue().connectionReady(mFeatureManager);
+
+        verify(mFeatureManager).updateCapabilities();
+        verify(mFeatureManager).registerImsRegistrationCallback(any());
+        verify(mMockFeature).onRcsConnected(mFeatureManager);
+
+        // Disconnect
+        mConnectorListener.getValue().connectionUnavailable();
+
+        verify(mFeatureManager).unregisterImsRegistrationCallback(any());
+        verify(mMockFeature, times(2)).onRcsDisconnected();
+    }
+
+    @Test
+    public void testFeatureManagerConnectedAddRemoveFeature() throws Exception {
+        RcsFeatureController controller = createFeatureController();
+        // Connect the RcsFeatureManager
+        mConnectorListener.getValue().connectionReady(mFeatureManager);
+        controller.addFeature(mMockFeature, RcsFeatureController.Feature.class);
+
+        verify(mMockFeature).onRcsConnected(mFeatureManager);
+        assertEquals(mMockFeature, controller.getFeature(RcsFeatureController.Feature.class));
+
+        controller.removeFeature(RcsFeatureController.Feature.class);
+        verify(mMockFeature).onDestroy();
+        assertNull(controller.getFeature(RcsFeatureController.Feature.class));
+    }
+
+    @Test
+    public void testFeatureManagerConnectedRegister() throws Exception {
+        RcsFeatureController controller = createFeatureController();
+        IImsRegistrationCallback regCb = mock(IImsRegistrationCallback.class);
+        IImsCapabilityCallback capCb = mock(IImsCapabilityCallback.class);
+        // Connect the RcsFeatureManager
+        mConnectorListener.getValue().connectionReady(mFeatureManager);
+
+        try {
+            controller.registerImsRegistrationCallback(0 /*subId*/, regCb);
+            controller.registerRcsAvailabilityCallback(0 /*subId*/, capCb);
+            controller.isCapable(RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE,
+                    ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+            controller.isAvailable(RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE);
+            controller.getRegistrationTech(integer -> {
+            });
+            verify(mFeatureManager).registerImsRegistrationCallback(0, regCb);
+            verify(mFeatureManager).registerRcsAvailabilityCallback(0, capCb);
+            verify(mFeatureManager).isCapable(
+                    RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE,
+                    ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+            verify(mFeatureManager).isAvailable(
+                    RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE);
+            verify(mFeatureManager).getImsRegistrationTech(any());
+        } catch (ImsException e) {
+            fail("ImsException not expected.");
+        }
+
+        controller.unregisterImsRegistrationCallback(0, regCb);
+        controller.unregisterRcsAvailabilityCallback(0, capCb);
+        verify(mFeatureManager).unregisterImsRegistrationCallback(0, regCb);
+        verify(mFeatureManager).unregisterRcsAvailabilityCallback(0, capCb);
+    }
+
+    @Test
+    public void testFeatureManagerConnectedHelper() throws Exception {
+        RcsFeatureController controller = createFeatureController();
+        // Connect the RcsFeatureManager
+        mConnectorListener.getValue().connectionReady(mFeatureManager);
+        ArgumentCaptor<IImsRegistrationCallback> captor =
+                ArgumentCaptor.forClass(IImsRegistrationCallback.class);
+        verify(mFeatureManager).registerImsRegistrationCallback(captor.capture());
+        assertNotNull(captor.getValue());
+
+        captor.getValue().onDeregistered(REASON_DISCONNECTED);
+        controller.getRegistrationState(result -> {
+            assertNotNull(result);
+            assertEquals(RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED, result.intValue());
+        });
+        verify(mRegistrationCallback).handleImsUnregistered(REASON_DISCONNECTED);
+
+        captor.getValue().onRegistering(ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+        controller.getRegistrationState(result -> {
+            assertNotNull(result);
+            assertEquals(RegistrationManager.REGISTRATION_STATE_REGISTERING, result.intValue());
+        });
+        verify(mRegistrationCallback).handleImsRegistering(
+                AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+        captor.getValue().onRegistered(ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+        controller.getRegistrationState(result -> {
+            assertNotNull(result);
+            assertEquals(RegistrationManager.REGISTRATION_STATE_REGISTERED, result.intValue());
+        });
+        verify(mRegistrationCallback).handleImsRegistered(
+                AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+    }
+
+    @Test
+    public void testFeatureManagerDisconnectedAddFeature() {
+        RcsFeatureController controller = createFeatureController();
+        // Disconnect the RcsFeatureManager
+        mConnectorListener.getValue().connectionUnavailable();
+        controller.addFeature(mMockFeature, RcsFeatureController.Feature.class);
+
+        verify(mMockFeature).onRcsDisconnected();
+    }
+
+    @Test
+    public void testFeatureManagerDisconnectedException() {
+        RcsFeatureController controller = createFeatureController();
+        IImsRegistrationCallback regCb = mock(IImsRegistrationCallback.class);
+        IImsCapabilityCallback capCb = mock(IImsCapabilityCallback.class);
+        // Disconnect the RcsFeatureManager
+        mConnectorListener.getValue().connectionUnavailable();
+
+        try {
+            controller.registerImsRegistrationCallback(0 /*subId*/, null /*callback*/);
+            fail("ImsException expected for IMS registration.");
+        } catch (ImsException e) {
+            //expected
+        }
+        try {
+            controller.registerRcsAvailabilityCallback(0 /*subId*/, null /*callback*/);
+            fail("ImsException expected for availability");
+        } catch (ImsException e) {
+            //expected
+        }
+        try {
+            controller.isCapable(RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE,
+                    ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+            fail("ImsException expected for capability check");
+        } catch (ImsException e) {
+            //expected
+        }
+        try {
+            controller.isAvailable(RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE);
+            fail("ImsException expected for availability check");
+        } catch (ImsException e) {
+            //expected
+        }
+        controller.getRegistrationTech(integer -> {
+            assertNotNull(integer);
+            assertEquals(ImsRegistrationImplBase.REGISTRATION_TECH_NONE, integer.intValue());
+        });
+        controller.unregisterImsRegistrationCallback(0, regCb);
+        controller.unregisterRcsAvailabilityCallback(0, capCb);
+        verify(mFeatureManager, never()).unregisterImsRegistrationCallback(0, regCb);
+        verify(mFeatureManager, never()).unregisterRcsAvailabilityCallback(0, capCb);
+    }
+
+    @Test
+    public void testChangeSubId() throws Exception {
+        RcsFeatureController controller = createFeatureController();
+        // Connect the RcsFeatureManager
+        mConnectorListener.getValue().connectionReady(mFeatureManager);
+        verify(mFeatureManager).updateCapabilities();
+        controller.addFeature(mMockFeature, RcsFeatureController.Feature.class);
+
+        controller.updateAssociatedSubscription(1 /*new sub id*/);
+
+        verify(mFeatureManager, times(2)).updateCapabilities();
+        verify(mMockFeature).onAssociatedSubscriptionUpdated(1 /*new sub id*/);
+    }
+
+    @Test
+    public void testDestroy() throws Exception {
+        RcsFeatureController controller = createFeatureController();
+        // Connect the RcsFeatureManager
+        mConnectorListener.getValue().connectionReady(mFeatureManager);
+        controller.addFeature(mMockFeature, RcsFeatureController.Feature.class);
+        controller.destroy();
+
+        verify(mFeatureConnector).disconnect();
+        verify(mMockFeature).onRcsDisconnected();
+        verify(mMockFeature).onDestroy();
+        assertNull(controller.getFeature(RcsFeatureController.Feature.class));
+    }
+
+    private RcsFeatureController createFeatureController() {
+        RcsFeatureController controller = new RcsFeatureController(mContext, 0 /*slotId*/,
+                mRegistrationFactory);
+        controller.setFeatureConnectorFactory(mFeatureFactory);
+        doReturn(mFeatureConnector).when(mFeatureFactory).create(any(), anyInt(),
+                mConnectorListener.capture(), any(), any());
+        controller.connect();
+        assertNotNull(mConnectorListener.getValue());
+        return controller;
+    }
+}
diff --git a/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java b/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java
new file mode 100644
index 0000000..cfb68b7
--- /dev/null
+++ b/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2020 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.rcs;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.TelephonyTestBase;
+import com.android.ims.FeatureConnector;
+import com.android.ims.RcsFeatureManager;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+
+@RunWith(AndroidJUnit4.class)
+public class TelephonyRcsServiceTest extends TelephonyTestBase {
+
+    @Captor ArgumentCaptor<BroadcastReceiver> mReceiverCaptor;
+    @Mock TelephonyRcsService.FeatureFactory mFeatureFactory;
+    @Mock UserCapabilityExchangeImpl mMockUceSlot0;
+    @Mock UserCapabilityExchangeImpl mMockUceSlot1;
+    @Mock RcsFeatureController.RegistrationHelperFactory mRegistrationFactory;
+    @Mock RcsFeatureController.FeatureConnectorFactory<RcsFeatureManager> mFeatureConnectorFactory;
+    @Mock FeatureConnector<RcsFeatureManager> mFeatureConnector;
+
+    private RcsFeatureController mFeatureControllerSlot0;
+    private RcsFeatureController mFeatureControllerSlot1;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        doReturn(mFeatureConnector).when(mFeatureConnectorFactory).create(any(), anyInt(),
+                any(), any(), any());
+        mFeatureControllerSlot0 = createFeatureController(0 /*slotId*/);
+        mFeatureControllerSlot1 = createFeatureController(1 /*slotId*/);
+        doReturn(mFeatureControllerSlot0).when(mFeatureFactory).createController(any(), eq(0));
+        doReturn(mFeatureControllerSlot1).when(mFeatureFactory).createController(any(), eq(1));
+        doReturn(mMockUceSlot0).when(mFeatureFactory).createUserCapabilityExchange(any(), eq(0),
+                anyInt());
+        doReturn(mMockUceSlot1).when(mFeatureFactory).createUserCapabilityExchange(any(), eq(1),
+                anyInt());
+        //set up default slot-> sub ID mappings.
+        setSlotToSubIdMapping(0 /*slotId*/, 1/*subId*/);
+        setSlotToSubIdMapping(1 /*slotId*/, 2/*subId*/);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    @Test
+    public void testUserCapabilityExchangePresenceConnected() {
+        setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true /*isEnabled*/);
+        createRcsService(1 /*numSlots*/);
+        verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
+        verify(mFeatureControllerSlot0).connect();
+    }
+
+    @Test
+    public void testUserCapabilityExchangeOptionsConnected() {
+        setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_SIP_OPTIONS_BOOL, true /*isEnabled*/);
+        createRcsService(1 /*numSlots*/);
+        verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
+        verify(mFeatureControllerSlot0).connect();
+    }
+
+    @Test
+    public void testNoFeaturesEnabled() {
+        createRcsService(1 /*numSlots*/);
+        // No carrier config set for UCE.
+        verify(mFeatureControllerSlot0, never()).addFeature(mMockUceSlot0,
+                UserCapabilityExchangeImpl.class);
+        verify(mFeatureControllerSlot0, never()).connect();
+    }
+
+    @Test
+    public void testNoFeaturesEnabledCarrierConfigChanged() {
+        createRcsService(1 /*numSlots*/);
+        // No carrier config set for UCE.
+
+        sendCarrierConfigChanged(0, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+        verify(mFeatureControllerSlot0, never()).addFeature(mMockUceSlot0,
+                UserCapabilityExchangeImpl.class);
+        verify(mFeatureControllerSlot0, never()).connect();
+        verify(mFeatureControllerSlot0, never()).updateAssociatedSubscription(anyInt());
+    }
+
+
+    @Test
+    public void testSlotUpdates() {
+        setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true /*isEnabled*/);
+        TelephonyRcsService service = createRcsService(1 /*numSlots*/);
+        verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
+        verify(mFeatureControllerSlot0).connect();
+
+        // there should be no changes if the new num slots = old num
+        service.updateFeatureControllerSize(1 /*newNumSlots*/);
+        verify(mFeatureControllerSlot0, times(1)).addFeature(mMockUceSlot0,
+                UserCapabilityExchangeImpl.class);
+        verify(mFeatureControllerSlot0, times(1)).connect();
+
+        // Add a new slot.
+        verify(mFeatureControllerSlot1, never()).addFeature(mMockUceSlot1,
+                UserCapabilityExchangeImpl.class);
+        verify(mFeatureControllerSlot1, never()).connect();
+        service.updateFeatureControllerSize(2 /*newNumSlots*/);
+        // This shouldn't have changed for slot 0.
+        verify(mFeatureControllerSlot0, times(1)).addFeature(mMockUceSlot0,
+                UserCapabilityExchangeImpl.class);
+        verify(mFeatureControllerSlot0, times(1)).connect();
+        verify(mFeatureControllerSlot1).addFeature(mMockUceSlot1, UserCapabilityExchangeImpl.class);
+        verify(mFeatureControllerSlot1, times(1)).connect();
+
+        // Remove a slot.
+        verify(mFeatureControllerSlot0, never()).destroy();
+        verify(mFeatureControllerSlot1, never()).destroy();
+        service.updateFeatureControllerSize(1 /*newNumSlots*/);
+        // addFeature/connect shouldn't have been called again
+        verify(mFeatureControllerSlot0, times(1)).addFeature(mMockUceSlot0,
+                UserCapabilityExchangeImpl.class);
+        verify(mFeatureControllerSlot0, times(1)).connect();
+        verify(mFeatureControllerSlot1, times(1)).addFeature(mMockUceSlot1,
+                UserCapabilityExchangeImpl.class);
+        verify(mFeatureControllerSlot1, times(1)).connect();
+        // Verify destroy is only called for slot 1.
+        verify(mFeatureControllerSlot0, never()).destroy();
+        verify(mFeatureControllerSlot1, times(1)).destroy();
+    }
+
+    @Test
+    public void testCarrierConfigUpdate() {
+        setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true /*isEnabled*/);
+        createRcsService(2 /*numSlots*/);
+        verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
+        verify(mFeatureControllerSlot1).addFeature(mMockUceSlot1, UserCapabilityExchangeImpl.class);
+        verify(mFeatureControllerSlot0).connect();
+        verify(mFeatureControllerSlot1).connect();
+
+
+        // Send carrier config update for each slot.
+        sendCarrierConfigChanged(0 /*slotId*/, 1 /*subId*/);
+        verify(mFeatureControllerSlot0).updateAssociatedSubscription(1);
+        verify(mFeatureControllerSlot1, never()).updateAssociatedSubscription(1);
+        sendCarrierConfigChanged(1 /*slotId*/, 2 /*subId*/);
+        verify(mFeatureControllerSlot0, never()).updateAssociatedSubscription(2);
+        verify(mFeatureControllerSlot1, times(1)).updateAssociatedSubscription(2);
+    }
+
+    @Test
+    public void testCarrierConfigUpdateUceToNoUce() {
+        setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true /*isEnabled*/);
+        createRcsService(1 /*numSlots*/);
+        verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
+        verify(mFeatureControllerSlot0).connect();
+
+
+        // Send carrier config update for each slot.
+        setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, false /*isEnabled*/);
+        sendCarrierConfigChanged(0 /*slotId*/, 1 /*subId*/);
+        verify(mFeatureControllerSlot0).removeFeature(UserCapabilityExchangeImpl.class);
+        verify(mFeatureControllerSlot0).updateAssociatedSubscription(1);
+    }
+
+    @Test
+    public void testCarrierConfigUpdateNoUceToUce() {
+        createRcsService(1 /*numSlots*/);
+        verify(mFeatureControllerSlot0, never()).addFeature(mMockUceSlot0,
+                UserCapabilityExchangeImpl.class);
+        verify(mFeatureControllerSlot0, never()).connect();
+
+
+        // Send carrier config update for each slot.
+        setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true /*isEnabled*/);
+        sendCarrierConfigChanged(0 /*slotId*/, 1 /*subId*/);
+        verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
+        verify(mFeatureControllerSlot0).connect();
+        verify(mFeatureControllerSlot0).updateAssociatedSubscription(1);
+    }
+
+    private void sendCarrierConfigChanged(int slotId, int subId) {
+        Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+        intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, slotId);
+        intent.putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, subId);
+        mReceiverCaptor.getValue().onReceive(mContext, intent);
+    }
+
+    private void setCarrierConfig(String key, boolean value) {
+        PersistableBundle bundle = mContext.getCarrierConfig();
+        bundle.putBoolean(key, value);
+    }
+
+    private void setSlotToSubIdMapping(int slotId, int loadedSubId) {
+        SubscriptionManager m = mContext.getSystemService(SubscriptionManager.class);
+        int [] subIds = new int[1];
+        subIds[0] = loadedSubId;
+        doReturn(subIds).when(m).getSubscriptionIds(eq(slotId));
+    }
+
+    private TelephonyRcsService createRcsService(int numSlots) {
+        TelephonyRcsService service = new TelephonyRcsService(mContext, numSlots);
+        service.setFeatureFactory(mFeatureFactory);
+        service.initialize();
+        verify(mContext).registerReceiver(mReceiverCaptor.capture(), any());
+        return service;
+    }
+
+    private RcsFeatureController createFeatureController(int slotId) {
+        // Create a spy instead of a mock because TelephonyRcsService relies on state provided by
+        // RcsFeatureController.
+        RcsFeatureController controller = spy(new RcsFeatureController(mContext, slotId,
+                mRegistrationFactory));
+        controller.setFeatureConnectorFactory(mFeatureConnectorFactory);
+        return controller;
+    }
+}