Merge "Allow the phone access to READ_CARRIER_APP_INFO"
diff --git a/Android.bp b/Android.bp
index a7ae0cc..72712b8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -31,13 +31,14 @@
         "androidx.preference_preference",
         "androidx.recyclerview_recyclerview",
         "androidx.legacy_legacy-preference-v14",
-        "guava",
         "android-support-annotations",
         "com.android.phone.common-lib",
+        "guava",
+        "PlatformProperties",
     ],
 
     srcs: [
-        ":framework-telephony-stack-shared-srcs",
+        ":framework-telephony-common-shared-srcs",
         "src/**/*.java",
         "sip/src/**/*.java",
         "ecc/proto/**/*.proto",
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 7e70d8b..813ad12 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -34,7 +34,6 @@
     <protected-broadcast android:name="android.intent.action.ANY_DATA_STATE" />
     <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.telephony.action.NETWORK_SET_TIME" />
     <protected-broadcast android:name="android.telephony.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" />
@@ -509,7 +508,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>
 
@@ -540,6 +539,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"
diff --git a/OWNERS b/OWNERS
index 5be6fe5..849347f 100644
--- a/OWNERS
+++ b/OWNERS
@@ -11,4 +11,5 @@
 shuoq@google.com
 paulye@google.com
 nazaninb@google.com
-sarahchin@google.com
\ No newline at end of file
+sarahchin@google.com
+dbright@google.com
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/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/config.xml b/res/values/config.xml
index 8c36b1a..6906089 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -257,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/styles.xml b/res/values/styles.xml
index d131bd8..e8a0bed 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -260,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">
@@ -268,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"
diff --git a/sip/src/com/android/services/telephony/sip/SipSettings.java b/sip/src/com/android/services/telephony/sip/SipSettings.java
index ded16df..700fe81 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,7 +239,7 @@
     }
 
     private void processActiveProfilesFromSipService() {
-        SipProfile[] activeList = {};
+        List<SipProfile> activeList = new ArrayList<>();
         try {
             activeList = mSipManager.getListOfProfiles();
         } catch (SipException 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/CallBarringEditPreference.java b/src/com/android/phone/CallBarringEditPreference.java
index edff1e3..4b89cd9 100644
--- a/src/com/android/phone/CallBarringEditPreference.java
+++ b/src/com/android/phone/CallBarringEditPreference.java
@@ -77,9 +77,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();
diff --git a/src/com/android/phone/CallNotifier.java b/src/com/android/phone/CallNotifier.java
index 9e7bb39..133545d 100644
--- a/src/com/android/phone/CallNotifier.java
+++ b/src/com/android/phone/CallNotifier.java
@@ -616,7 +616,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);
@@ -768,8 +768,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 0256726..0052cd0 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -39,13 +39,13 @@
 import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
-import android.os.ServiceManager;
 import android.preference.PreferenceManager;
 import android.service.carrier.CarrierIdentifier;
 import android.service.carrier.CarrierService;
 import android.service.carrier.ICarrierService;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyFrameworkInitializer;
 import android.telephony.TelephonyManager;
 import android.util.LocalLog;
 import android.util.Log;
@@ -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";
 
@@ -149,10 +143,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";
 
@@ -547,7 +539,8 @@
         mServiceConnection = new CarrierServiceConnection[numPhones];
         mHasSentConfigChange = new boolean[numPhones];
         // Make this service available through ServiceManager.
-        ServiceManager.addService(Context.CARRIER_CONFIG_SERVICE, this);
+        TelephonyFrameworkInitializer
+                .getTelephonyServiceManager().getCarrierConfigServiceRegisterer().register(this);
         log("CarrierConfigLoader has started");
         mSubscriptionInfoUpdater = PhoneFactory.getSubscriptionInfoUpdater();
         mHandler.sendEmptyMessage(EVENT_CHECK_SYSTEM_UPDATE);
@@ -793,27 +786,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 +838,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 +855,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());
         }
diff --git a/src/com/android/phone/EmergencyCallbackModeService.java b/src/com/android/phone/EmergencyCallbackModeService.java
index 41d83c4..7e68255 100644
--- a/src/com/android/phone/EmergencyCallbackModeService.java
+++ b/src/com/android/phone/EmergencyCallbackModeService.java
@@ -31,6 +31,7 @@
 import android.os.IBinder;
 import android.os.Message;
 import android.sysprop.TelephonyProperties;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 
 import com.android.internal.telephony.Phone;
@@ -119,7 +120,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();
                 }
             }
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index 7531aca..119c71b 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;
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..ffac202 100644
--- a/src/com/android/phone/ImsRcsController.java
+++ b/src/com/android/phone/ImsRcsController.java
@@ -16,23 +16,27 @@
 
 package com.android.phone;
 
-import android.content.Context;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
+import android.telephony.TelephonyFrameworkInitializer;
 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.ImsManager;
 import com.android.ims.RcsFeatureManager;
+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.TelephonyRcsService;
 
 import java.util.List;
 
@@ -46,6 +50,7 @@
     private static ImsRcsController sInstance;
 
     private PhoneGlobals mApp;
+    private TelephonyRcsService mRcsService;
 
     /**
      * Initialize the singleton ImsRcsController instance.
@@ -66,7 +71,88 @@
     private ImsRcsController(PhoneGlobals app) {
         Log.i(TAG, "ImsRcsController");
         mApp = app;
-        ServiceManager.addService(Context.TELEPHONY_IMS_SERVICE, this);
+        TelephonyFrameworkInitializer
+                .getTelephonyServiceManager().getTelephonyImsServiceRegisterer().register(this);
+    }
+
+    /**
+     * Register a IImsRegistrationCallback to receive IMS network registration state.
+     */
+    @Override
+    public void registerImsRegistrationCallback(int subId, IImsRegistrationCallback callback)
+            throws RemoteException {
+        enforceReadPrivilegedPermission("registerImsRegistrationCallback");
+        final long token = Binder.clearCallingIdentity();
+        try {
+            getRcsFeatureManager(subId).registerImsRegistrationCallback(callback);
+        } catch (com.android.ims.ImsException e) {
+            Log.e(TAG, "registerImsRegistrationCallback: sudId=" + subId + ", " + e.getMessage());
+            throw new ServiceSpecificException(e.getCode());
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    /**
+     * Removes an existing {@link RegistrationCallback}.
+     */
+    @Override
+    public void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback callback) {
+        enforceReadPrivilegedPermission("unregisterImsRegistrationCallback");
+        final long token = Binder.clearCallingIdentity();
+        try {
+            getRcsFeatureManager(subId).unregisterImsRegistrationCallback(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 {
+            getImsPhone(subId).getImsRcsRegistrationState(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 {
+            getImsPhone(subId).getImsRcsRegistrationTech(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);
+        }
     }
 
     /**
@@ -202,13 +288,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,7 +306,32 @@
         }
         ImsPhone imsPhone = (ImsPhone) phone.getImsPhone();
         if (imsPhone == null) {
+            throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
+                    "Cannot find ImsPhone instance: " + subId);
+        }
+        return imsPhone;
+    }
+
+    /**
+     * Retrieve RcsFeatureManager instance.
+     *
+     * @param subId the subscription ID
+     * @return The RcsFeatureManager instance
+     * @throws ServiceSpecificException if getting RcsFeatureManager instance failed.
+     */
+    private RcsFeatureManager getRcsFeatureManager(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,
+                    "Invalid subscription Id: " + subId);
+        }
+        ImsPhone imsPhone = (ImsPhone) phone.getImsPhone();
+        if (imsPhone == null) {
+            throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
                     "Cannot find ImsPhone instance: " + subId);
         }
         RcsFeatureManager rcsFeatureManager = imsPhone.getRcsManager();
@@ -226,4 +341,8 @@
         }
         return rcsFeatureManager;
     }
+
+    void setRcsService(TelephonyRcsService rcsService) {
+        mRcsService = rcsService;
+    }
 }
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index b81e77f..a369423 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -71,6 +71,7 @@
 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;
 
@@ -149,6 +150,7 @@
     CallerInfoCache callerInfoCache;
     NotificationMgr notificationMgr;
     ImsResolver mImsResolver;
+    TelephonyRcsService mTelephonyRcsService;
     public PhoneInterfaceManager phoneMgr;
     public ImsRcsController imsRcsController;
     CarrierConfigLoader configLoader;
@@ -303,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 =
@@ -372,6 +374,11 @@
 
             imsRcsController = ImsRcsController.init(this);
 
+            if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS)) {
+                mTelephonyRcsService = new TelephonyRcsService(this);
+                imsRcsController.setRcsService(mTelephonyRcsService);
+            }
+
             configLoader = CarrierConfigLoader.init(this);
 
             // Create the CallNotifier singleton, which handles
@@ -403,7 +410,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);
@@ -662,7 +669,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 {
@@ -708,7 +716,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));
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index c8ff261..ad517ee 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -51,7 +51,6 @@
 import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
-import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -84,11 +83,11 @@
 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;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyFrameworkInitializer;
 import android.telephony.TelephonyHistogram;
 import android.telephony.TelephonyManager;
 import android.telephony.TelephonyScanManager;
@@ -110,6 +109,7 @@
 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;
@@ -173,6 +173,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;
@@ -266,6 +267,10 @@
     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;
 
     // Parameters of select command.
     private static final int SELECT_COMMAND = 0xA4;
@@ -1230,6 +1235,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;
@@ -1412,7 +1454,10 @@
     private void publish() {
         if (DBG) log("publish: " + this);
 
-        ServiceManager.addService("phone", this);
+        TelephonyFrameworkInitializer
+                .getTelephonyServiceManager()
+                .getTelephonyServiceRegisterer()
+                .register(this);
     }
 
     private Phone getPhoneFromRequest(MainThreadRequest request) {
@@ -1453,6 +1498,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);
     }
@@ -2965,10 +3020,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 {
+        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
         enforceReadPrivilegedPermission("registerImsRegistrationCallback");
+
         if (!ImsManager.isImsSupportedOnDevice(mApp)) {
             throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
                     "IMS not available on device.");
@@ -2985,8 +3047,14 @@
         }
     }
 
+    /**
+     * 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) {
+        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
         enforceReadPrivilegedPermission("unregisterImsRegistrationCallback");
         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
             throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
@@ -3043,6 +3111,7 @@
      */
     @Override
     public void getImsMmTelRegistrationTransportType(int subId, IIntegerConsumer consumer) {
+        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
         enforceReadPrivilegedPermission("getImsMmTelRegistrationTransportType");
         if (!ImsManager.isImsSupportedOnDevice(mApp)) {
             throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
@@ -3074,9 +3143,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 registerMmTelCapabilityCallback(int subId, IImsCapabilityCallback c)
             throws RemoteException {
+        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
         enforceReadPrivilegedPermission("registerMmTelCapabilityCallback");
         if (!ImsManager.isImsSupportedOnDevice(mApp)) {
             throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
@@ -3094,8 +3169,14 @@
         }
     }
 
+    /**
+     * 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) {
+        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
         enforceReadPrivilegedPermission("unregisterMmTelCapabilityCallback");
         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
             throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
@@ -3186,9 +3267,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");
+        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
+        enforceReadPrivilegedPermission("isAdvancedCallingSettingEnabled");
+
         // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
         final long token = Binder.clearCallingIdentity();
         try {
@@ -3217,8 +3304,13 @@
         }
     }
 
+    /**
+     * 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) {
+        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
         enforceReadPrivilegedPermission("isVtSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -3246,8 +3338,13 @@
         }
     }
 
+    /**
+     * 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) {
+        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
         enforceReadPrivilegedPermission("isVoWiFiSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -3276,8 +3373,13 @@
         }
     }
 
+    /**
+     * 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) {
+        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
         enforceReadPrivilegedPermission("isVoWiFiRoamingSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -3323,8 +3425,13 @@
         }
     }
 
+    /**
+     * 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) {
+        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
         enforceReadPrivilegedPermission("getVoWiFiModeSetting");
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -3400,8 +3507,13 @@
         }
     }
 
+    /**
+     * 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) {
+        //TODO: b/147498511 will add TelephonyPermissions#checkCallingOrSelfReadPrecisePhoneState
         enforceReadPrivilegedPermission("isTtyOverVolteEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -3420,6 +3532,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);
@@ -3451,6 +3567,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) {
@@ -3458,18 +3659,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;
             }
 
@@ -3507,8 +3701,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. ");
                 }
             }
 
@@ -3527,16 +3722,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;
             }
 
@@ -3562,8 +3748,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.");
                 }
             }
 
@@ -3672,6 +3859,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)) {
@@ -3924,9 +4134,9 @@
     @Override
     public int getLteOnCdmaModeForSubscriber(int subId, String callingPackage,
             String callingFeatureId) {
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, callingFeatureId,
-                "getLteOnCdmaModeForSubscriber")) {
+        try {
+            enforceReadPrivilegedPermission("getLteOnCdmaModeForSubscriber");
+        } catch (SecurityException e) {
             return PhoneConstants.LTE_ON_CDMA_UNKNOWN;
         }
 
@@ -4958,21 +5168,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.
@@ -5076,24 +5346,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 {
@@ -7142,7 +7403,8 @@
 
     @Override
     public int getCdmaRoamingMode(int subId) {
-        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+        TelephonyPermissions
+                .enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
                 mApp, subId, "getCdmaRoamingMode");
 
         final long identity = Binder.clearCallingIdentity();
@@ -7568,6 +7830,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.
      *
@@ -7628,6 +7899,9 @@
 
     @Override
     public void enqueueSmsPickResult(String callingPackage, 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")) {
@@ -7742,4 +8016,112 @@
             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 an integer representing the status of IccLock enabled or disabled in the following
+     * three cases:
+     *   - {@link TelephonyManager#CHANGE_ICC_LOCK_SUCCESS} if enabled or disabled IccLock
+     *   successfully.
+     *   - Positive number and zero for remaining password attempts.
+     *   - Negative number for other failure cases (such like enabling/disabling PIN failed).
+     *
+     */
+    @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 an integer representing the status of IccLock changed in the following three cases:
+     *   - {@link TelephonyManager#CHANGE_ICC_LOCK_SUCCESS} if changed IccLock successfully.
+     *   - Positive number and zero for remaining password attempts.
+     *   - Negative number for other failure cases (such like enabling/disabling PIN failed).
+     *
+     */
+    @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 c865f14..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;
diff --git a/src/com/android/phone/ServiceStateProvider.java b/src/com/android/phone/ServiceStateProvider.java
index 9e6ea83..00269e0 100644
--- a/src/com/android/phone/ServiceStateProvider.java
+++ b/src/com/android/phone/ServiceStateProvider.java
@@ -61,6 +61,8 @@
 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,
@@ -128,7 +130,7 @@
 
     @Override
     public Uri insert(Uri uri, ContentValues values) {
-        if (uri.isPathPrefixMatch(CONTENT_URI)) {
+        if (isPathPrefixMatch(uri, CONTENT_URI)) {
             // Parse the subId
             int subId = 0;
             try {
@@ -183,7 +185,7 @@
     @Override
     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
             String sortOrder) {
-        if (!uri.isPathPrefixMatch(CONTENT_URI)) {
+        if (!isPathPrefixMatch(uri, CONTENT_URI)) {
             throw new IllegalArgumentException("Invalid URI: " + uri);
         } else {
             // Parse the subId
@@ -362,4 +364,29 @@
             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;
+    }
 }
diff --git a/src/com/android/services/telephony/ConferenceParticipantConnection.java b/src/com/android/services/telephony/ConferenceParticipantConnection.java
index ed92e7f..ac3928f 100644
--- a/src/com/android/services/telephony/ConferenceParticipantConnection.java
+++ b/src/com/android/services/telephony/ConferenceParticipantConnection.java
@@ -19,7 +19,7 @@
 import android.net.Uri;
 import android.telecom.Connection;
 import android.telecom.DisconnectCause;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
 import android.telephony.SubscriptionInfo;
 import android.text.TextUtils;
 
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index 4c3f9c9..e8386e8 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -30,7 +30,7 @@
 import android.telecom.VideoProfile;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
 import android.util.Pair;
 
 import com.android.ims.internal.ConferenceParticipant;
diff --git a/src/com/android/services/telephony/ImsConferenceController.java b/src/com/android/services/telephony/ImsConferenceController.java
index 1e10055..5445cc4 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;
diff --git a/src/com/android/services/telephony/PstnIncomingCallNotifier.java b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
index 2dfeaed..69e4020 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;
@@ -278,7 +278,12 @@
             if (((ImsPhoneConnection) connection).isRttEnabledForCall()) {
                 extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, true);
             }
+            if (((ImsPhoneConnection) connection).isIncomingCallAutoRejected()) {
+                extras.putString(TelecomManager.EXTRA_CALL_DISCONNECT_MESSAGE,
+                        "Call Dropped by lower layers");
+            }
         }
+
         PhoneAccountHandle handle = findCorrectPhoneAccountHandle();
         if (handle == null) {
             try {
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 5a1e6a6..bd789c5 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -41,7 +41,7 @@
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneStateListener;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -226,6 +226,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 +235,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;
 
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 14f0cb8..7d7b72b 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -40,7 +40,7 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.ServiceState.RilRadioTechnology;
 import android.telephony.SubscriptionManager;
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index ac3827f..69a2672 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -1471,6 +1471,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.
@@ -1539,7 +1545,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);
             }
diff --git a/src/com/android/services/telephony/rcs/PresenceHelper.java b/src/com/android/services/telephony/rcs/PresenceHelper.java
new file mode 100644
index 0000000..5f7e35f
--- /dev/null
+++ b/src/com/android/services/telephony/rcs/PresenceHelper.java
@@ -0,0 +1,166 @@
+/*
+ * 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.Nullable;
+import android.content.Context;
+import android.telephony.SubscriptionManager;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.ims.RcsFeatureConnection;
+import com.android.ims.RcsFeatureManager;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.imsphone.ImsPhone;
+import com.android.internal.telephony.imsphone.ImsRcsStatusListener;
+import com.android.phone.R;
+import com.android.service.ims.presence.PresencePublication;
+import com.android.service.ims.presence.PresenceSubscriber;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+class PresenceHelper {
+
+    private static final String LOG_TAG = "PresenceHelper";
+
+    private final Context mContext;
+    private final List<Phone> mPhones;
+
+    private final SparseArray<PresencePublication> mPresencePublications = new SparseArray<>();
+    private final SparseArray<PresenceSubscriber> mPresenceSubscribers = new SparseArray<>();
+
+    PresenceHelper(Context context) {
+        mContext = context;
+
+        // Get phones
+        Phone[] phoneAry = PhoneFactory.getPhones();
+        mPhones = (phoneAry != null) ? Arrays.asList(phoneAry) : new ArrayList<>();
+
+        initRcsPresencesInstance();
+        registerRcsConnectionStatus();
+
+        Log.i(LOG_TAG, "initialized: phone size=" + mPhones.size());
+    }
+
+    private void initRcsPresencesInstance() {
+        String[] volteError = mContext.getResources().getStringArray(
+                R.array.config_volte_provision_error_on_publish_response);
+        String[] rcsError = mContext.getResources().getStringArray(
+                R.array.config_rcs_provision_error_on_publish_response);
+
+        mPhones.forEach((phone) -> {
+            RcsFeatureConnection rcsConnection = getRcsFeatureConnection(phone);
+            // Initialize PresencePublication
+            mPresencePublications.put(
+                    phone.getPhoneId(),
+                    new PresencePublication(rcsConnection, mContext, volteError, rcsError));
+            // Initialize PresenceSubscriber
+            mPresenceSubscribers.put(
+                    phone.getPhoneId(),
+                    new PresenceSubscriber(rcsConnection, mContext, volteError, rcsError));
+        });
+    }
+
+    private @Nullable RcsFeatureConnection getRcsFeatureConnection(Phone phone) {
+        ImsPhone imsPhone = (ImsPhone) phone.getImsPhone();
+        if (imsPhone != null) {
+            RcsFeatureManager rcsFeatureManager = imsPhone.getRcsManager();
+            if (rcsFeatureManager != null) {
+                return rcsFeatureManager.getRcsFeatureConnection();
+            }
+        }
+        return null;
+    }
+
+    /*
+     * RcsFeatureManager in ImsPhone is not null only when RCS is connected. Register a callback to
+     * receive the RCS connection status.
+     */
+    private void registerRcsConnectionStatus() {
+        mPhones.forEach((phone) -> {
+            ImsPhone imsPhone = (ImsPhone) phone.getImsPhone();
+            if (imsPhone != null) {
+                imsPhone.setRcsStatusListener(mStatusListener);
+            }
+        });
+    }
+
+    /**
+     * The IMS RCS status listener to listen the status changed
+     */
+    private ImsRcsStatusListener mStatusListener = new ImsRcsStatusListener() {
+        @Override
+        public void onRcsConnected(int phoneId, RcsFeatureManager rcsFeatureManager) {
+            int subId = getSubscriptionId(phoneId);
+            if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+                Log.e(LOG_TAG, "onRcsConnected: invalid subId, phoneId=" + phoneId);
+                return;
+            }
+
+            Log.i(LOG_TAG, "onRcsConnected: phoneId=" + phoneId + ", subId=" + subId);
+            RcsFeatureConnection connection = rcsFeatureManager.getRcsFeatureConnection();
+            PresencePublication presencePublication = getPresencePublication(phoneId);
+            if (presencePublication != null) {
+                Log.i(LOG_TAG, "Update PresencePublisher because RCS is connected");
+                presencePublication.updatePresencePublisher(subId, connection);
+            }
+            PresenceSubscriber presenceSubscriber = getPresenceSubscriber(phoneId);
+            if (presenceSubscriber != null) {
+                Log.i(LOG_TAG, "Update PresenceSubscriber because RCS is connected");
+                presenceSubscriber.updatePresenceSubscriber(subId, connection);
+            }
+        }
+
+        @Override
+        public void onRcsDisconnected(int phoneId) {
+            int subId = getSubscriptionId(phoneId);
+            Log.i(LOG_TAG, "onRcsDisconnected: phoneId=" + phoneId + ", subId=" + subId);
+            PresencePublication publication = getPresencePublication(phoneId);
+            if (publication != null) {
+                Log.i(LOG_TAG, "Remove PresencePublisher because RCS is disconnected");
+                publication.removePresencePublisher(subId);
+            }
+
+            PresenceSubscriber subscriber = getPresenceSubscriber(phoneId);
+            if (subscriber != null) {
+                Log.i(LOG_TAG, "Remove PresencePublisher because RCS is disconnected");
+                subscriber.removePresenceSubscriber(subId);
+            }
+        }
+    };
+
+    private int getSubscriptionId(int phoneId) {
+        Optional<Phone> phone = mPhones.stream()
+                .filter(p -> p.getPhoneId() == phoneId).findFirst();
+        if (phone.isPresent()) {
+            return phone.get().getSubId();
+        }
+        return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+    }
+
+    public @Nullable PresencePublication getPresencePublication(int phoneId) {
+        return mPresencePublications.get(phoneId);
+    }
+
+    public @Nullable PresenceSubscriber getPresenceSubscriber(int phoneId) {
+        return mPresenceSubscribers.get(phoneId);
+    }
+}
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..74765d6
--- /dev/null
+++ b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
@@ -0,0 +1,50 @@
+/*
+ * 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.util.Log;
+
+import com.android.service.ims.presence.PresencePublication;
+import com.android.service.ims.presence.PresenceSubscriber;
+
+/**
+ * Telephony RCS Service integrates PresencePublication and PresenceSubscriber into the service.
+ */
+public class TelephonyRcsService {
+
+    private static final String LOG_TAG = "TelephonyRcsService";
+
+    private final Context mContext;
+
+    // A helper class to manage the RCS Presences instances.
+    private final PresenceHelper mPresenceHelper;
+
+    public TelephonyRcsService(Context context) {
+        Log.i(LOG_TAG, "initialize");
+        mContext = context;
+        mPresenceHelper = new PresenceHelper(mContext);
+    }
+
+    private PresencePublication getPresencePublication(int phoneId) {
+        return mPresenceHelper.getPresencePublication(phoneId);
+    }
+
+    private PresenceSubscriber getPresenceSubscriber(int phoneId) {
+        return mPresenceHelper.getPresenceSubscriber(phoneId);
+    }
+}
diff --git a/tests/src/com/android/phone/tests/CallDialTest.java b/tests/src/com/android/phone/tests/CallDialTest.java
index b30f5b2..6e78be0 100644
--- a/tests/src/com/android/phone/tests/CallDialTest.java
+++ b/tests/src/com/android/phone/tests/CallDialTest.java
@@ -22,9 +22,9 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.telecom.PhoneAccount;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyFrameworkInitializer;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
@@ -155,7 +155,11 @@
         log("==> number: '" + number + "'");
 
         try {
-            ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
+            ITelephony phone = ITelephony.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getTelephonyServiceRegisterer()
+                            .get());
             log("- phone: " + phone);
             log("- calling call()...");
             phone.call(getPackageName(), number);
@@ -173,7 +177,11 @@
         log("==> number: '" + number + "'");
 
         try {
-            ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
+            ITelephony phone = ITelephony.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getTelephonyServiceRegisterer()
+                            .get());
             log("- phone: " + phone);
             log("- calling dial()...");
             phone.dial(number);