Merge "Change the condition strictly for comparing address"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 0da698e..9f90866 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -50,7 +50,7 @@
     <protected-broadcast android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
     <protected-broadcast android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
     <protected-broadcast android:name="android.provider.Telephony.SMS_CB_RECEIVED" />
-    <protected-broadcast android:name="android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED" />
+    <protected-broadcast android:name="android.provider.action.SMS_EMERGENCY_CB_RECEIVED" />
     <protected-broadcast android:name="android.provider.Telephony.SECRET_CODE" />
     <protected-broadcast android:name= "com.android.internal.stk.command" />
     <protected-broadcast android:name= "com.android.internal.stk.session_end" />
@@ -457,6 +457,21 @@
             </intent-filter>
         </activity>
 
+        <!--
+            Handler for EuiccManager's public action intents. These are public and do not require
+            any special permissions to start, although the calling package name should be
+            whitelisted by the underlying eUICC service implementation (i.e. the LPA).
+        -->
+        <activity android:name=".euicc.EuiccPublicActionUiDispatcherActivity"
+            android:theme="@android:style/Theme.NoDisplay">
+            <!-- Max out priority to ensure nobody else will handle these intents. -->
+            <intent-filter android:priority="1000">
+                <action android:name=
+                    "android.telephony.euicc.action.START_EUICC_ACTIVATION" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="EmergencyCallbackModeExitDialog"
             android:excludeFromRecents="true"
             android:label="@string/ecm_exit_dialog"
diff --git a/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java b/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java
index ec77ff1..1cf7f4b 100644
--- a/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java
+++ b/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java
@@ -126,7 +126,7 @@
      * @param context The context.
      */
     void verifyAndPurgeInvalidPhoneAccounts(Context context) {
-        TelecomManager telecomManager = TelecomManager.from(context);
+        TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
         SipProfileDb profileDb = new SipProfileDb(context);
         List<PhoneAccountHandle> accountHandles = telecomManager.getPhoneAccountsSupportingScheme(
                 PhoneAccount.SCHEME_SIP);
@@ -188,7 +188,8 @@
 
         // Un-register its PhoneAccount.
         PhoneAccountHandle handle = SipUtil.createAccountHandle(context, sipProfileName);
-        TelecomManager.from(context).unregisterPhoneAccount(handle);
+        TelecomManager tm = context.getSystemService(TelecomManager.class);
+        tm.unregisterPhoneAccount(handle);
     }
 
     /**
@@ -235,7 +236,7 @@
     private void startSipProfiles(Context context, String sipProfileName, boolean enableProfile) {
         final SipPreferences sipPreferences = new SipPreferences(context);
         boolean isReceivingCalls = sipPreferences.isReceivingCallsEnabled();
-        TelecomManager telecomManager = TelecomManager.from(context);
+        TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
         SipManager sipManager = SipManager.newInstance(context);
         SipProfileDb profileDb = new SipProfileDb(context);
         List<SipProfile> sipProfileList = profileDb.retrieveSipProfileList();
diff --git a/sip/src/com/android/services/telephony/sip/SipIncomingCallReceiver.java b/sip/src/com/android/services/telephony/sip/SipIncomingCallReceiver.java
index 19f5882..3212c00 100644
--- a/sip/src/com/android/services/telephony/sip/SipIncomingCallReceiver.java
+++ b/sip/src/com/android/services/telephony/sip/SipIncomingCallReceiver.java
@@ -73,7 +73,7 @@
         if (accountHandle != null) {
             Bundle extras = new Bundle();
             extras.putParcelable(SipUtil.EXTRA_INCOMING_CALL_INTENT, intent);
-            TelecomManager tm = TelecomManager.from(context);
+            TelecomManager tm = context.getSystemService(TelecomManager.class);
             PhoneAccount phoneAccount = tm.getPhoneAccount(accountHandle);
             if (phoneAccount != null && phoneAccount.isEnabled()) {
                 tm.addNewIncomingCall(accountHandle, extras);
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index 29df8b8..3858595 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -214,7 +214,7 @@
         mSubscriptionInfoHelper.setActionBarTitle(
                 getActionBar(), getResources(), R.string.call_settings_with_label);
         mPhone = mSubscriptionInfoHelper.getPhone();
-        mTelecomManager = TelecomManager.from(this);
+        mTelecomManager = getSystemService(TelecomManager.class);
     }
 
     private void updateImsManager(Phone phone) {
@@ -229,8 +229,8 @@
     }
 
     private void listenPhoneState(boolean listen) {
-        TelephonyManager telephonyManager =
-                (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
+        TelephonyManager telephonyManager = getSystemService(TelephonyManager.class)
+                .createForSubscriptionId(mPhone.getSubId());
         telephonyManager.listen(mPhoneStateListener, listen
                 ? PhoneStateListener.LISTEN_CALL_STATE : PhoneStateListener.LISTEN_NONE);
     }
@@ -239,10 +239,7 @@
         @Override
         public void onCallStateChanged(int state, String incomingNumber) {
             if (DBG) log("PhoneStateListener onCallStateChanged: state is " + state);
-            // Use TelecomManager#getCallStete instead of 'state' parameter because it needs
-            // to check the current state of all phone calls.
-            boolean isCallStateIdle =
-                    mTelecomManager.getCallState() == TelephonyManager.CALL_STATE_IDLE;
+            boolean isCallStateIdle = state == TelephonyManager.CALL_STATE_IDLE;
             if (mEnableVideoCalling != null) {
                 mEnableVideoCalling.setEnabled(isCallStateIdle);
             }
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 1d0138b..874c412 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -141,6 +141,8 @@
     private static final int EVENT_FETCH_CARRIER_TIMEOUT = 15;
     // SubscriptionInfoUpdater has finished updating the sub for the carrier config.
     private static final int EVENT_SUBSCRIPTION_INFO_UPDATED = 16;
+    // Multi-SIM config changed.
+    private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 17;
 
     private static final int BIND_TIMEOUT_MILLIS = 30000;
 
@@ -174,28 +176,21 @@
         public void handleMessage(Message msg) {
             final int phoneId = msg.arg1;
             logWithLocalLog("mHandler: " + msg.what + " phoneId: " + phoneId);
+            if (!SubscriptionManager.isValidPhoneId(phoneId)
+                    && msg.what != EVENT_MULTI_SIM_CONFIG_CHANGED) {
+                return;
+            }
             switch (msg.what) {
                 case EVENT_CLEAR_CONFIG:
                 {
-                    /* Ignore clear configuration request if device is being shutdown. */
-                    Phone phone = PhoneFactory.getPhone(phoneId);
-                    if (phone != null) {
-                        if (phone.isShuttingDown()) {
-                            break;
-                        }
-                    }
-
-                    mConfigFromDefaultApp[phoneId] = null;
-                    mConfigFromCarrierApp[phoneId] = null;
-                    mServiceConnection[phoneId] = null;
-                    broadcastConfigChangedIntent(phoneId, false);
+                    clearConfigForPhone(phoneId, true);
                     break;
                 }
 
                 case EVENT_SYSTEM_UNLOCKED:
                 {
-                    for (int i = 0; i < TelephonyManager.from(mContext)
-                            .getSupportedModemCount(); ++i) {
+                    for (int i = 0; i < TelephonyManager.from(mContext).getActiveModemCount();
+                            ++i) {
                         // When user unlock device, we should only try to send broadcast again if we
                         // have sent it before unlock. This will avoid we try to load carrier config
                         // when SIM is still loading when unlock happens.
@@ -212,8 +207,7 @@
                     // Only update if there are cached config removed to avoid updating config for
                     // unrelated packages.
                     if (clearCachedConfigForPackage(carrierPackageName)) {
-                        int numPhones = TelephonyManager.from(mContext)
-                                .getSupportedModemCount();
+                        int numPhones = TelephonyManager.from(mContext).getActiveModemCount();
                         for (int i = 0; i < numPhones; ++i) {
                             updateConfigForPhoneId(i);
                         }
@@ -496,6 +490,9 @@
                 case EVENT_SUBSCRIPTION_INFO_UPDATED:
                     broadcastConfigChangedIntent(phoneId);
                     break;
+                case EVENT_MULTI_SIM_CONFIG_CHANGED:
+                    onMultiSimConfigChanged();
+                    break;
             }
         }
     }
@@ -555,6 +552,23 @@
         }
     }
 
+    private void clearConfigForPhone(int phoneId, boolean sendBroadcast) {
+        /* Ignore clear configuration request if device is being shutdown. */
+        Phone phone = PhoneFactory.getPhone(phoneId);
+        if (phone != null) {
+            if (phone.isShuttingDown()) {
+                return;
+            }
+        }
+
+        mConfigFromDefaultApp[phoneId] = null;
+        mConfigFromCarrierApp[phoneId] = null;
+        mServiceConnection[phoneId] = null;
+        mHasSentConfigChange[phoneId] = false;
+
+        if (sendBroadcast) broadcastConfigChangedIntent(phoneId, false);
+    }
+
     private void notifySubscriptionInfoUpdater(int phoneId) {
         String configPackagename;
         PersistableBundle configToSend;
@@ -572,6 +586,7 @@
         // mOverrideConfigs is for testing. And it will override current configs.
         PersistableBundle config = mOverrideConfigs[phoneId];
         if (config != null) {
+            configToSend = new PersistableBundle(configToSend);
             configToSend.putAll(config);
         }
 
@@ -919,6 +934,13 @@
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_DO_FETCH_DEFAULT, phoneId, -1));
     }
 
+    private void onMultiSimConfigChanged() {
+        for (int i = TelephonyManager.from(mContext).getActiveModemCount();
+                i < mConfigFromDefaultApp.length; i++) {
+            clearConfigForPhone(i, false);
+        }
+    }
+
     @Override
     public @NonNull PersistableBundle getConfigForSubId(int subId, String callingPackage) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
diff --git a/src/com/android/phone/ImsRcsController.java b/src/com/android/phone/ImsRcsController.java
new file mode 100644
index 0000000..d1ff56f
--- /dev/null
+++ b/src/com/android/phone/ImsRcsController.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.ServiceManager;
+import android.telephony.ims.aidl.IImsCapabilityCallback;
+import android.telephony.ims.aidl.IImsRcsController;
+import android.telephony.ims.aidl.IRcsUceControllerCallback;
+import android.telephony.ims.feature.RcsFeature;
+import android.util.Log;
+
+import java.util.List;
+
+/**
+ * Implementation of the IImsRcsController interface.
+ */
+public class ImsRcsController extends IImsRcsController.Stub {
+    private static final String TAG = "ImsRcsController";
+
+    /** The singleton instance. */
+    private static ImsRcsController sInstance;
+
+    private PhoneGlobals mApp;
+
+    /**
+     * Initialize the singleton ImsRcsController instance.
+     * This is only done once, at startup, from PhoneApp.onCreate().
+     */
+    static ImsRcsController init(PhoneGlobals app) {
+        synchronized (ImsRcsController.class) {
+            if (sInstance == null) {
+                sInstance = new ImsRcsController(app);
+            } else {
+                Log.wtf(TAG, "init() called multiple times!  sInstance = " + sInstance);
+            }
+            return sInstance;
+        }
+    }
+
+    /** Private constructor; @see init() */
+    private ImsRcsController(PhoneGlobals app) {
+        Log.i(TAG, "ImsRcsController");
+        mApp = app;
+        ServiceManager.addService(Context.TELEPHONY_IMS_SERVICE, this);
+    }
+
+    @Override
+    public void registerRcsAvailabilityCallback(IImsCapabilityCallback c) {
+        enforceReadPrivilegedPermission("registerRcsAvailabilityCallback");
+    }
+
+    @Override
+    public void unregisterRcsAvailabilityCallback(IImsCapabilityCallback c) {
+        enforceReadPrivilegedPermission("unregisterRcsAvailabilityCallback");
+    }
+
+    @Override
+    public boolean isCapable(int subId,
+            @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
+        enforceReadPrivilegedPermission("isCapable");
+        return false;
+    }
+
+    @Override
+    public boolean isAvailable(int subId,
+            @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
+        enforceReadPrivilegedPermission("isAvailable");
+        return false;
+    }
+
+    @Override
+    public void requestCapabilities(int subId, List<Uri> contactNumbers,
+            IRcsUceControllerCallback c) {
+        enforceReadPrivilegedPermission("requestCapabilities");
+    }
+
+    @Override
+    public int getUcePublishState(int subId) {
+        enforceReadPrivilegedPermission("getUcePublishState");
+        return -1;
+    }
+
+    @Override
+    public boolean isUceSettingEnabled(int subId) {
+        enforceReadPrivilegedPermission("isUceSettingEnabled");
+        return false;
+    }
+
+    @Override
+    public void setUceSettingEnabled(int subId, boolean isEnabled) {
+        enforceModifyPermission();
+    }
+
+    /**
+     * Make sure either called from same process as self (phone) or IPC caller has read privilege.
+     *
+     * @throws SecurityException if the caller does not have the required permission
+     */
+    private void enforceReadPrivilegedPermission(String message) {
+        mApp.enforceCallingOrSelfPermission(
+                android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, message);
+    }
+
+    /**
+     * Make sure the caller has the MODIFY_PHONE_STATE permission.
+     *
+     * @throws SecurityException if the caller does not have the required permission
+     */
+    private void enforceModifyPermission() {
+        mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
+    }
+}
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index 475cc1f..d35d9a6 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -42,7 +42,6 @@
 import android.preference.PreferenceManager;
 import android.provider.ContactsContract.PhoneLookup;
 import android.provider.Settings;
-import android.telecom.DefaultDialerManager;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
@@ -164,7 +163,7 @@
                 (StatusBarManager) app.getSystemService(Context.STATUS_BAR_SERVICE);
         mUserManager = (UserManager) app.getSystemService(Context.USER_SERVICE);
         mSubscriptionManager = SubscriptionManager.from(mContext);
-        mTelecomManager = TelecomManager.from(mContext);
+        mTelecomManager = app.getSystemService(TelecomManager.class);
         mTelephonyManager = (TelephonyManager) app.getSystemService(Context.TELEPHONY_SERVICE);
     }
 
@@ -472,8 +471,8 @@
     }
 
     private Intent getShowVoicemailIntentForDefaultDialer(UserHandle userHandle) {
-        String dialerPackage = DefaultDialerManager
-                .getDefaultDialerApplication(mContext, userHandle.getIdentifier());
+        String dialerPackage = mContext.getSystemService(TelecomManager.class)
+                .getDefaultDialerPackage(userHandle.getIdentifier());
         return new Intent(TelephonyManager.ACTION_SHOW_VOICEMAIL_NOTIFICATION)
                 .setPackage(dialerPackage);
     }
diff --git a/src/com/android/phone/PhoneDisplayMessage.java b/src/com/android/phone/PhoneDisplayMessage.java
index 2b86a61..199fbb8 100644
--- a/src/com/android/phone/PhoneDisplayMessage.java
+++ b/src/com/android/phone/PhoneDisplayMessage.java
@@ -78,10 +78,11 @@
         sDisplayMessageDialog.getWindow().setType(
                 WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
         sDisplayMessageDialog.getWindow().addFlags(
-                WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+                WindowManager.LayoutParams.FLAG_DIM_BEHIND
+                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
 
         sDisplayMessageDialog.show();
-        PhoneGlobals.getInstance().wakeUpScreen();
     }
 
     /**
@@ -91,6 +92,9 @@
         if (DBG) log("Dissmissing Display Info Record...");
 
         if (sDisplayMessageDialog != null) {
+            sDisplayMessageDialog.getWindow().clearFlags(
+                    WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+                    | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
             sDisplayMessageDialog.dismiss();
             sDisplayMessageDialog = null;
         }
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index c46d09b..1eb5f50 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -37,7 +37,6 @@
 import android.os.Message;
 import android.os.PersistableBundle;
 import android.os.PowerManager;
-import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserManager;
 import android.preference.PreferenceManager;
@@ -148,6 +147,7 @@
     CallerInfoCache callerInfoCache;
     NotificationMgr notificationMgr;
     public PhoneInterfaceManager phoneMgr;
+    public ImsRcsController imsRcsController;
     CarrierConfigLoader configLoader;
 
     private Phone phoneInEcm;
@@ -354,6 +354,8 @@
 
             phoneMgr = PhoneInterfaceManager.init(this);
 
+            imsRcsController = ImsRcsController.init(this);
+
             configLoader = CarrierConfigLoader.init(this);
 
             // Create the CallNotifier singleton, which handles
@@ -367,6 +369,10 @@
             // register for MMI/USSD
             mCM.registerForMmiComplete(mHandler, MMI_COMPLETE, null);
 
+            // Initialize cell status using current airplane mode.
+            handleAirplaneModeChange(this, Settings.Global.getInt(getContentResolver(),
+                    Settings.Global.AIRPLANE_MODE_ON, AIRPLANE_OFF));
+
             // Register for misc other intent broadcasts.
             IntentFilter intentFilter =
                     new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
@@ -498,19 +504,6 @@
         mPUKEntryProgressDialog = dialog;
     }
 
-    /**
-     * If we are not currently keeping the screen on, then poke the power
-     * manager to wake up the screen for the user activity timeout duration.
-     */
-    /* package */ void wakeUpScreen() {
-        synchronized (this) {
-            if (mWakeState == WakeState.SLEEP) {
-                if (DBG) Log.d(LOG_TAG, "pulse screen lock");
-                mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.phone:WAKE");
-            }
-        }
-    }
-
     KeyguardManager getKeyguardManager() {
         return mKeyguardManager;
     }
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index cfbcafb..0ed2a7a 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -1077,11 +1077,13 @@
                     try {
                         if (ar.exception != null) {
                             Log.e(LOG_TAG, "Exception retrieving CellInfo=" + ar.exception);
-                            cb.onError(TelephonyManager.CellInfoCallback.ERROR_MODEM_ERROR,
-                                    new android.os.ParcelableException(ar.exception));
+                            cb.onError(
+                                    TelephonyManager.CellInfoCallback.ERROR_MODEM_ERROR,
+                                    ar.exception.getClass().getName(),
+                                    ar.exception.toString());
                         } else if (ar.result == null) {
                             Log.w(LOG_TAG, "Timeout Waiting for CellInfo!");
-                            cb.onError(TelephonyManager.CellInfoCallback.ERROR_TIMEOUT, null);
+                            cb.onError(TelephonyManager.CellInfoCallback.ERROR_TIMEOUT, null, null);
                         } else {
                             // use the result as returned
                             cb.onCellInfo((List<CellInfo>) ar.result);
@@ -2635,7 +2637,8 @@
     @Override
     public Bundle getVisualVoicemailSettings(String callingPackage, int subId) {
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
-        String systemDialer = TelecomManager.from(mApp).getSystemDialerPackage();
+        TelecomManager tm = mApp.getSystemService(TelecomManager.class);
+        String systemDialer = tm.getSystemDialerPackage();
         if (!TextUtils.equals(callingPackage, systemDialer)) {
             throw new SecurityException("caller must be system dialer");
         }
@@ -2861,8 +2864,8 @@
     public void sendDialerSpecialCode(String callingPackage, String inputCode) {
         final Phone defaultPhone = getDefaultPhone();
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
-        String defaultDialer = TelecomManager.from(defaultPhone.getContext())
-                .getDefaultDialerPackage();
+        TelecomManager tm = defaultPhone.getContext().getSystemService(TelecomManager.class);
+        String defaultDialer = tm.getDefaultDialerPackage();
         if (!TextUtils.equals(callingPackage, defaultDialer)) {
             TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(
                     getDefaultSubscription(), "sendDialerSpecialCode");
@@ -4897,7 +4900,7 @@
      * @hide
      */
     @Override
-    public boolean getTetherApnRequiredForSubscriber(int subId) {
+    public boolean isTetheringApnRequiredForSubscriber(int subId) {
         enforceModifyPermission();
         final long identity = Binder.clearCallingIdentity();
         final Phone phone = getPhone(subId);
@@ -5030,6 +5033,52 @@
         }
     }
 
+    private int getCarrierPrivilegeStatusFromCarrierConfigRules(int privilegeFromSim,
+            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);
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            SubscriptionInfo subInfo = subController.getSubscriptionInfo(phone.getSubId());
+            SubscriptionManager subManager = (SubscriptionManager)
+                    phone.getContext().getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+            for (String pkg : packages) {
+                if (subManager.canManageSubscription(subInfo, pkg)) {
+                    return TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+                }
+            }
+            return privilegeFromSim;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private int getCarrierPrivilegeStatusFromCarrierConfigRules(int privilegeFromSim, Phone phone,
+            String pkgName) {
+        //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;
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            SubscriptionInfo subInfo = subController.getSubscriptionInfo(phone.getSubId());
+            SubscriptionManager subManager = (SubscriptionManager)
+                    phone.getContext().getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+            return subManager.canManageSubscription(subInfo, pkgName)
+                ? TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS : privilegeFromSim;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     @Override
     public int getCarrierPrivilegeStatus(int subId) {
         final Phone phone = getPhone(subId);
@@ -5042,8 +5091,10 @@
             loge("getCarrierPrivilegeStatus: No UICC");
             return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
         }
-        return card.getCarrierPrivilegeStatusForCurrentTransaction(
-                phone.getContext().getPackageManager());
+
+        return getCarrierPrivilegeStatusFromCarrierConfigRules(
+            card.getCarrierPrivilegeStatusForCurrentTransaction(
+                phone.getContext().getPackageManager()), phone);
     }
 
     @Override
@@ -5059,7 +5110,9 @@
             loge("getCarrierPrivilegeStatusForUid: No UICC");
             return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
         }
-        return profile.getCarrierPrivilegeStatusForUid(phone.getContext().getPackageManager(), uid);
+        return getCarrierPrivilegeStatusFromCarrierConfigRules(
+            profile.getCarrierPrivilegeStatusForUid(
+                phone.getContext().getPackageManager(), uid), phone);
     }
 
     @Override
@@ -5074,8 +5127,9 @@
             loge("checkCarrierPrivilegesForPackage: No UICC on subId " + subId);
             return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
         }
-
-        return card.getCarrierPrivilegeStatus(mApp.getPackageManager(), pkgName);
+        return getCarrierPrivilegeStatusFromCarrierConfigRules(
+            card.getCarrierPrivilegeStatus(mApp.getPackageManager(), pkgName),
+            getPhone(phoneId), pkgName);
     }
 
     @Override
@@ -5090,7 +5144,9 @@
               continue;
             }
 
-            result = card.getCarrierPrivilegeStatus(mApp.getPackageManager(), pkgName);
+            result = getCarrierPrivilegeStatusFromCarrierConfigRules(
+                card.getCarrierPrivilegeStatus(mApp.getPackageManager(), pkgName),
+                getPhone(i), pkgName);
             if (result == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
                 break;
             }
@@ -5125,9 +5181,9 @@
                 if (packages == null) {
                     // Only check packages in user 0 for now
                     packages = pm.getInstalledPackagesAsUser(
-                            PackageManager.MATCH_DISABLED_COMPONENTS
-                                    | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                                    | PackageManager.GET_SIGNATURES, UserHandle.USER_SYSTEM);
+                        PackageManager.MATCH_DISABLED_COMPONENTS
+                            | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+                            | PackageManager.GET_SIGNATURES, UserHandle.USER_SYSTEM);
                 }
                 for (int p = packages.size() - 1; p >= 0; p--) {
                     PackageInfo pkgInfo = packages.get(p);
@@ -5561,7 +5617,7 @@
 
     @Override
     public boolean isTtyModeSupported() {
-        TelecomManager telecomManager = TelecomManager.from(mApp);
+        TelecomManager telecomManager = mApp.getSystemService(TelecomManager.class);
         return telecomManager.isTtySupported();
     }
 
@@ -6020,8 +6076,8 @@
             PhoneAccountHandle phoneAccountHandle, Uri uri) {
         final Phone defaultPhone = getDefaultPhone();
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
-        if (!TextUtils.equals(callingPackage,
-                TelecomManager.from(defaultPhone.getContext()).getDefaultDialerPackage())) {
+        TelecomManager tm = defaultPhone.getContext().getSystemService(TelecomManager.class);
+        if (!TextUtils.equals(callingPackage, tm.getDefaultDialerPackage())) {
             TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
                     mApp, PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccountHandle),
                     "setVoicemailRingtoneUri");
@@ -6077,8 +6133,8 @@
             PhoneAccountHandle phoneAccountHandle, boolean enabled) {
         final Phone defaultPhone = getDefaultPhone();
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
-        if (!TextUtils.equals(callingPackage,
-                TelecomManager.from(defaultPhone.getContext()).getDefaultDialerPackage())) {
+        TelecomManager tm = defaultPhone.getContext().getSystemService(TelecomManager.class);
+        if (!TextUtils.equals(callingPackage, tm.getDefaultDialerPackage())) {
             TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
                     mApp, PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccountHandle),
                     "setVoicemailVibrationEnabled");
@@ -6421,7 +6477,8 @@
     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
             String[] args, ShellCallback callback, ResultReceiver resultReceiver)
             throws RemoteException {
-        (new TelephonyShellCommand(this)).exec(this, in, out, err, args, callback, resultReceiver);
+        (new TelephonyShellCommand(this, getDefaultPhone().getContext()))
+                .exec(this, in, out, err, args, callback, resultReceiver);
     }
 
     /**
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index 6c3f0bf..9835ba1 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -31,6 +31,7 @@
 import android.telecom.VideoProfile;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
 import android.text.TextUtils;
 import android.util.Log;
@@ -43,10 +44,7 @@
 import android.widget.Toast;
 
 import com.android.internal.telephony.Call;
-import com.android.internal.telephony.CallManager;
 import com.android.internal.telephony.CallStateException;
-import android.telephony.CallerInfo;
-import android.telephony.CallerInfoAsyncQuery;
 import com.android.internal.telephony.Connection;
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.MmiCode;
@@ -54,10 +52,8 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.TelephonyCapabilities;
-import com.android.phone.CallGatewayManager.RawGatewayInfo;
 import com.android.phone.settings.SuppServicesUiUtil;
 
-import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -131,79 +127,35 @@
     }
 
     /**
-     * @see placeCall below
-     */
-    public static int placeCall(Context context, Phone phone, String number, Uri contactRef,
-            boolean isEmergencyCall) {
-        return placeCall(context, phone, number, contactRef, isEmergencyCall,
-                CallGatewayManager.EMPTY_INFO, null);
-    }
-
-    /**
      * Dial the number using the phone passed in.
      *
-     * If the connection is establised, this method issues a sync call
-     * that may block to query the caller info.
-     * TODO: Change the logic to use the async query.
-     *
      * @param context To perform the CallerInfo query.
      * @param phone the Phone object.
      * @param number to be dialed as requested by the user. This is
      * NOT the phone number to connect to. It is used only to build the
      * call card and to update the call log. See above for restrictions.
-     * @param contactRef that triggered the call. Typically a 'tel:'
-     * uri but can also be a 'content://contacts' one.
-     * @param isEmergencyCall indicates that whether or not this is an
-     * emergency call
-     * @param gatewayUri Is the address used to setup the connection, null
-     * if not using a gateway
-     * @param callGateway Class for setting gateway data on a successful call.
      *
      * @return either CALL_STATUS_DIALED or CALL_STATUS_FAILED
      */
-    public static int placeCall(Context context, Phone phone, String number, Uri contactRef,
-            boolean isEmergencyCall, RawGatewayInfo gatewayInfo, CallGatewayManager callGateway) {
-        final Uri gatewayUri = gatewayInfo.gatewayUri;
+    public static int placeOtaspCall(Context context, Phone phone, String number) {
+        final Uri gatewayUri = null;
 
         if (VDBG) {
             log("placeCall()... number: '" + number + "'"
-                    + ", GW:'" + gatewayUri + "'"
-                    + ", contactRef:" + contactRef
-                    + ", isEmergencyCall: " + isEmergencyCall);
+                    + ", GW:'" + gatewayUri + "'");
         } else {
             log("placeCall()... number: " + toLogSafePhoneNumber(number)
-                    + ", GW: " + (gatewayUri != null ? "non-null" : "null")
-                    + ", emergency? " + isEmergencyCall);
+                    + ", GW: " + (gatewayUri != null ? "non-null" : "null"));
         }
         final PhoneGlobals app = PhoneGlobals.getInstance();
 
         boolean useGateway = false;
-        if (null != gatewayUri &&
-            !isEmergencyCall &&
-            PhoneUtils.isRoutableViaGateway(number)) {  // Filter out MMI, OTA and other codes.
-            useGateway = true;
-        }
+        Uri contactRef = null;
 
         int status = CALL_STATUS_DIALED;
         Connection connection;
         String numberToDial;
-        if (useGateway) {
-            // TODO: 'tel' should be a constant defined in framework base
-            // somewhere (it is in webkit.)
-            if (null == gatewayUri || !PhoneAccount.SCHEME_TEL.equals(gatewayUri.getScheme())) {
-                Log.e(LOG_TAG, "Unsupported URL:" + gatewayUri);
-                return CALL_STATUS_FAILED;
-            }
-
-            // We can use getSchemeSpecificPart because we don't allow #
-            // in the gateway numbers (treated a fragment delim.) However
-            // if we allow more complex gateway numbers sequence (with
-            // passwords or whatnot) that use #, this may break.
-            // TODO: Need to support MMI codes.
-            numberToDial = gatewayUri.getSchemeSpecificPart();
-        } else {
-            numberToDial = number;
-        }
+        numberToDial = number;
 
         try {
             connection = app.mCM.dial(phone, numberToDial, VideoProfile.STATE_AUDIO_ONLY);
@@ -228,33 +180,6 @@
             if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
                 updateCdmaCallStateOnNewOutgoingCall(app, connection);
             }
-
-            if (gatewayUri == null) {
-                // phone.dial() succeeded: we're now in a normal phone call.
-                // attach the URI to the CallerInfo Object if it is there,
-                // otherwise just attach the Uri Reference.
-                // if the uri does not have a "content" scheme, then we treat
-                // it as if it does NOT have a unique reference.
-                String content = context.getContentResolver().SCHEME_CONTENT;
-                if ((contactRef != null) && (contactRef.getScheme().equals(content))) {
-                    Object userDataObject = connection.getUserData();
-                    if (userDataObject == null) {
-                        connection.setUserData(contactRef);
-                    } else {
-                        // TODO: This branch is dead code, we have
-                        // just created the connection which has
-                        // no user data (null) by default.
-                        if (userDataObject instanceof CallerInfo) {
-                        ((CallerInfo) userDataObject).contactRefUri = contactRef;
-                        } else {
-                        ((CallerInfoToken) userDataObject).currentInfo.contactRefUri =
-                            contactRef;
-                        }
-                    }
-                }
-            }
-
-            startGetCallerInfo(context, connection, null, null, gatewayInfo);
         }
 
         return status;
@@ -299,7 +224,7 @@
                                           MmiCode mmiCode,
                                           Message buttonCallbackMessage,
                                           Dialog previousAlert) {
-        log("displayMMIInitiate: " + android.telecom.Log.pii(mmiCode.toString()));
+        log("displayMMIInitiate: " + Rlog.pii(LOG_TAG, mmiCode.toString()));
         if (previousAlert != null) {
             previousAlert.dismiss();
         }
@@ -662,533 +587,12 @@
         return canceled;
     }
 
-    /**
-     * Returns the caller-id info corresponding to the specified Connection.
-     * (This is just a simple wrapper around CallerInfo.getCallerInfo(): we
-     * extract a phone number from the specified Connection, and feed that
-     * number into CallerInfo.getCallerInfo().)
-     *
-     * The returned CallerInfo may be null in certain error cases, like if the
-     * specified Connection was null, or if we weren't able to get a valid
-     * phone number from the Connection.
-     *
-     * Finally, if the getCallerInfo() call did succeed, we save the resulting
-     * CallerInfo object in the "userData" field of the Connection.
-     *
-     * NOTE: This API should be avoided, with preference given to the
-     * asynchronous startGetCallerInfo API.
-     */
-    static CallerInfo getCallerInfo(Context context, Connection c) {
-        CallerInfo info = null;
-
-        if (c != null) {
-            //See if there is a URI attached.  If there is, this means
-            //that there is no CallerInfo queried yet, so we'll need to
-            //replace the URI with a full CallerInfo object.
-            Object userDataObject = c.getUserData();
-            if (userDataObject instanceof Uri) {
-                info = CallerInfo.getCallerInfo(context, (Uri) userDataObject);
-                if (info != null) {
-                    c.setUserData(info);
-                }
-            } else {
-                if (userDataObject instanceof CallerInfoToken) {
-                    //temporary result, while query is running
-                    info = ((CallerInfoToken) userDataObject).currentInfo;
-                } else {
-                    //final query result
-                    info = (CallerInfo) userDataObject;
-                }
-                if (info == null) {
-                    // No URI, or Existing CallerInfo, so we'll have to make do with
-                    // querying a new CallerInfo using the connection's phone number.
-                    String number = c.getAddress();
-
-                    if (DBG) log("getCallerInfo: number = " + toLogSafePhoneNumber(number));
-
-                    if (!TextUtils.isEmpty(number)) {
-                        info = CallerInfo.getCallerInfo(context, number);
-                        if (info != null) {
-                            c.setUserData(info);
-                        }
-                    }
-                }
-            }
-        }
-        return info;
-    }
-
-    /**
-     * Class returned by the startGetCallerInfo call to package a temporary
-     * CallerInfo Object, to be superceded by the CallerInfo Object passed
-     * into the listener when the query with token mAsyncQueryToken is complete.
-     */
-    public static class CallerInfoToken {
-        /**indicates that there will no longer be updates to this request.*/
-        public boolean isFinal;
-
-        public CallerInfo currentInfo;
-        public CallerInfoAsyncQuery asyncQuery;
-    }
-
-    /**
-     * place a temporary callerinfo object in the hands of the caller and notify
-     * caller when the actual query is done.
-     */
-    static CallerInfoToken startGetCallerInfo(Context context, Connection c,
-            CallerInfoAsyncQuery.OnQueryCompleteListener listener, Object cookie,
-            RawGatewayInfo info) {
-        CallerInfoToken cit;
-
-        if (c == null) {
-            //TODO: perhaps throw an exception here.
-            cit = new CallerInfoToken();
-            cit.asyncQuery = null;
-            return cit;
-        }
-
-        Object userDataObject = c.getUserData();
-
-        // There are now 3 states for the Connection's userData object:
-        //
-        //   (1) Uri - query has not been executed yet
-        //
-        //   (2) CallerInfoToken - query is executing, but has not completed.
-        //
-        //   (3) CallerInfo - query has executed.
-        //
-        // In each case we have slightly different behaviour:
-        //   1. If the query has not been executed yet (Uri or null), we start
-        //      query execution asynchronously, and note it by attaching a
-        //      CallerInfoToken as the userData.
-        //   2. If the query is executing (CallerInfoToken), we've essentially
-        //      reached a state where we've received multiple requests for the
-        //      same callerInfo.  That means that once the query is complete,
-        //      we'll need to execute the additional listener requested.
-        //   3. If the query has already been executed (CallerInfo), we just
-        //      return the CallerInfo object as expected.
-        //   4. Regarding isFinal - there are cases where the CallerInfo object
-        //      will not be attached, like when the number is empty (caller id
-        //      blocking).  This flag is used to indicate that the
-        //      CallerInfoToken object is going to be permanent since no
-        //      query results will be returned.  In the case where a query
-        //      has been completed, this flag is used to indicate to the caller
-        //      that the data will not be updated since it is valid.
-        //
-        //      Note: For the case where a number is NOT retrievable, we leave
-        //      the CallerInfo as null in the CallerInfoToken.  This is
-        //      something of a departure from the original code, since the old
-        //      code manufactured a CallerInfo object regardless of the query
-        //      outcome.  From now on, we will append an empty CallerInfo
-        //      object, to mirror previous behaviour, and to avoid Null Pointer
-        //      Exceptions.
-
-        if (userDataObject instanceof Uri) {
-            // State (1): query has not been executed yet
-
-            //create a dummy callerinfo, populate with what we know from URI.
-            cit = new CallerInfoToken();
-            cit.currentInfo = new CallerInfo();
-            cit.asyncQuery = CallerInfoAsyncQuery.startQuery(QUERY_TOKEN, context,
-                    (Uri) userDataObject, sCallerInfoQueryListener, c);
-            cit.asyncQuery.addQueryListener(QUERY_TOKEN, listener, cookie);
-            cit.isFinal = false;
-
-            c.setUserData(cit);
-
-            if (DBG) log("startGetCallerInfo: query based on Uri: " + userDataObject);
-
-        } else if (userDataObject == null) {
-            // No URI, or Existing CallerInfo, so we'll have to make do with
-            // querying a new CallerInfo using the connection's phone number.
-            String number = c.getAddress();
-
-            if (info != null && info != CallGatewayManager.EMPTY_INFO) {
-                // Gateway number, the connection number is actually the gateway number.
-                // need to lookup via dialed number.
-                number = info.trueNumber;
-            }
-
-            if (DBG) {
-                log("PhoneUtils.startGetCallerInfo: new query for phone number...");
-                log("- number (address): " + toLogSafePhoneNumber(number));
-                log("- c: " + c);
-                log("- phone: " + c.getCall().getPhone());
-                int phoneType = c.getCall().getPhone().getPhoneType();
-                log("- phoneType: " + phoneType);
-                switch (phoneType) {
-                    case PhoneConstants.PHONE_TYPE_NONE: log("  ==> PHONE_TYPE_NONE"); break;
-                    case PhoneConstants.PHONE_TYPE_GSM: log("  ==> PHONE_TYPE_GSM"); break;
-                    case PhoneConstants.PHONE_TYPE_IMS: log("  ==> PHONE_TYPE_IMS"); break;
-                    case PhoneConstants.PHONE_TYPE_CDMA: log("  ==> PHONE_TYPE_CDMA"); break;
-                    case PhoneConstants.PHONE_TYPE_SIP: log("  ==> PHONE_TYPE_SIP"); break;
-                    case PhoneConstants.PHONE_TYPE_THIRD_PARTY:
-                        log("  ==> PHONE_TYPE_THIRD_PARTY");
-                        break;
-                    default: log("  ==> Unknown phone type"); break;
-                }
-            }
-
-            cit = new CallerInfoToken();
-            cit.currentInfo = new CallerInfo();
-
-            // Store CNAP information retrieved from the Connection (we want to do this
-            // here regardless of whether the number is empty or not).
-            cit.currentInfo.cnapName =  c.getCnapName();
-            cit.currentInfo.setName(cit.currentInfo.cnapName); // This can still get overwritten
-                                                             // by ContactInfo later
-            cit.currentInfo.numberPresentation = c.getNumberPresentation();
-            cit.currentInfo.namePresentation = c.getCnapNamePresentation();
-
-            if (VDBG) {
-                log("startGetCallerInfo: number = " + number);
-                log("startGetCallerInfo: CNAP Info from FW(1): name="
-                    + cit.currentInfo.cnapName
-                    + ", Name/Number Pres=" + cit.currentInfo.numberPresentation);
-            }
-
-            // handling case where number is null (caller id hidden) as well.
-            if (!TextUtils.isEmpty(number)) {
-                // Check for special CNAP cases and modify the CallerInfo accordingly
-                // to be sure we keep the right information to display/log later
-                number = modifyForSpecialCnapCases(context, cit.currentInfo, number,
-                        cit.currentInfo.numberPresentation);
-
-                cit.currentInfo.setPhoneNumber(number);
-                // For scenarios where we may receive a valid number from the network but a
-                // restricted/unavailable presentation, we do not want to perform a contact query
-                // (see note on isFinal above). So we set isFinal to true here as well.
-                if (cit.currentInfo.numberPresentation != PhoneConstants.PRESENTATION_ALLOWED) {
-                    cit.isFinal = true;
-                } else {
-                    if (DBG) log("==> Actually starting CallerInfoAsyncQuery.startQuery()...");
-                    cit.asyncQuery = CallerInfoAsyncQuery.startQuery(QUERY_TOKEN, context,
-                            number, sCallerInfoQueryListener, c);
-                    cit.asyncQuery.addQueryListener(QUERY_TOKEN, listener, cookie);
-                    cit.isFinal = false;
-                }
-            } else {
-                // This is the case where we are querying on a number that
-                // is null or empty, like a caller whose caller id is
-                // blocked or empty (CLIR).  The previous behaviour was to
-                // throw a null CallerInfo object back to the user, but
-                // this departure is somewhat cleaner.
-                if (DBG) log("startGetCallerInfo: No query to start, send trivial reply.");
-                cit.isFinal = true; // please see note on isFinal, above.
-            }
-
-            c.setUserData(cit);
-
-            if (DBG) {
-                log("startGetCallerInfo: query based on number: " + toLogSafePhoneNumber(number));
-            }
-
-        } else if (userDataObject instanceof CallerInfoToken) {
-            // State (2): query is executing, but has not completed.
-
-            // just tack on this listener to the queue.
-            cit = (CallerInfoToken) userDataObject;
-
-            // handling case where number is null (caller id hidden) as well.
-            if (cit.asyncQuery != null) {
-                cit.asyncQuery.addQueryListener(QUERY_TOKEN, listener, cookie);
-
-                if (DBG) log("startGetCallerInfo: query already running, adding listener: " +
-                        listener.getClass().toString());
-            } else {
-                // handling case where number/name gets updated later on by the network
-                String updatedNumber = c.getAddress();
-
-                if (info != null) {
-                    // Gateway number, the connection number is actually the gateway number.
-                    // need to lookup via dialed number.
-                    updatedNumber = info.trueNumber;
-                }
-
-                if (DBG) {
-                    log("startGetCallerInfo: updatedNumber initially = "
-                            + toLogSafePhoneNumber(updatedNumber));
-                }
-                if (!TextUtils.isEmpty(updatedNumber)) {
-                    // Store CNAP information retrieved from the Connection
-                    cit.currentInfo.cnapName =  c.getCnapName();
-                    // This can still get overwritten by ContactInfo
-                    cit.currentInfo.setName(cit.currentInfo.cnapName);
-                    cit.currentInfo.numberPresentation = c.getNumberPresentation();
-                    cit.currentInfo.namePresentation = c.getCnapNamePresentation();
-
-                    updatedNumber = modifyForSpecialCnapCases(context, cit.currentInfo,
-                            updatedNumber, cit.currentInfo.numberPresentation);
-
-                    cit.currentInfo.setPhoneNumber(updatedNumber);
-                    if (DBG) {
-                        log("startGetCallerInfo: updatedNumber="
-                                + toLogSafePhoneNumber(updatedNumber));
-                    }
-                    if (VDBG) {
-                        log("startGetCallerInfo: CNAP Info from FW(2): name="
-                                + cit.currentInfo.cnapName
-                                + ", Name/Number Pres=" + cit.currentInfo.numberPresentation);
-                    } else if (DBG) {
-                        log("startGetCallerInfo: CNAP Info from FW(2)");
-                    }
-                    // For scenarios where we may receive a valid number from the network but a
-                    // restricted/unavailable presentation, we do not want to perform a contact query
-                    // (see note on isFinal above). So we set isFinal to true here as well.
-                    if (cit.currentInfo.numberPresentation != PhoneConstants.PRESENTATION_ALLOWED) {
-                        cit.isFinal = true;
-                    } else {
-                        cit.asyncQuery = CallerInfoAsyncQuery.startQuery(QUERY_TOKEN, context,
-                                updatedNumber, sCallerInfoQueryListener, c);
-                        cit.asyncQuery.addQueryListener(QUERY_TOKEN, listener, cookie);
-                        cit.isFinal = false;
-                    }
-                } else {
-                    if (DBG) log("startGetCallerInfo: No query to attach to, send trivial reply.");
-                    if (cit.currentInfo == null) {
-                        cit.currentInfo = new CallerInfo();
-                    }
-                    // Store CNAP information retrieved from the Connection
-                    cit.currentInfo.cnapName = c.getCnapName();  // This can still get
-                                                                 // overwritten by ContactInfo
-                    cit.currentInfo.setName(cit.currentInfo.cnapName);
-                    cit.currentInfo.numberPresentation = c.getNumberPresentation();
-                    cit.currentInfo.namePresentation = c.getCnapNamePresentation();
-
-                    if (VDBG) {
-                        log("startGetCallerInfo: CNAP Info from FW(3): name="
-                                + cit.currentInfo.cnapName
-                                + ", Name/Number Pres=" + cit.currentInfo.numberPresentation);
-                    } else if (DBG) {
-                        log("startGetCallerInfo: CNAP Info from FW(3)");
-                    }
-                    cit.isFinal = true; // please see note on isFinal, above.
-                }
-            }
-        } else {
-            // State (3): query is complete.
-
-            // The connection's userDataObject is a full-fledged
-            // CallerInfo instance.  Wrap it in a CallerInfoToken and
-            // return it to the user.
-
-            cit = new CallerInfoToken();
-            cit.currentInfo = (CallerInfo) userDataObject;
-            cit.asyncQuery = null;
-            cit.isFinal = true;
-            // since the query is already done, call the listener.
-            if (DBG) log("startGetCallerInfo: query already done, returning CallerInfo");
-            if (DBG) log("==> cit.currentInfo = " + cit.currentInfo);
-        }
-        return cit;
-    }
-
-    /**
-     * Static CallerInfoAsyncQuery.OnQueryCompleteListener instance that
-     * we use with all our CallerInfoAsyncQuery.startQuery() requests.
-     */
-    private static final int QUERY_TOKEN = -1;
-    static CallerInfoAsyncQuery.OnQueryCompleteListener sCallerInfoQueryListener =
-        new CallerInfoAsyncQuery.OnQueryCompleteListener () {
-            /**
-             * When the query completes, we stash the resulting CallerInfo
-             * object away in the Connection's "userData" (where it will
-             * later be retrieved by the in-call UI.)
-             */
-            public void onQueryComplete(int token, Object cookie, CallerInfo ci) {
-                if (DBG) log("query complete, updating connection.userdata");
-                Connection conn = (Connection) cookie;
-
-                // Added a check if CallerInfo is coming from ContactInfo or from Connection.
-                // If no ContactInfo, then we want to use CNAP information coming from network
-                if (DBG) log("- onQueryComplete: CallerInfo:" + ci);
-                if (ci.contactExists || ci.isEmergencyNumber() || ci.isVoiceMailNumber()) {
-                    // If the number presentation has not been set by
-                    // the ContactInfo, use the one from the
-                    // connection.
-
-                    // TODO: Need a new util method to merge the info
-                    // from the Connection in a CallerInfo object.
-                    // Here 'ci' is a new CallerInfo instance read
-                    // from the DB. It has lost all the connection
-                    // info preset before the query (see PhoneUtils
-                    // line 1334). We should have a method to merge
-                    // back into this new instance the info from the
-                    // connection object not set by the DB. If the
-                    // Connection already has a CallerInfo instance in
-                    // userData, then we could use this instance to
-                    // fill 'ci' in. The same routine could be used in
-                    // PhoneUtils.
-                    if (0 == ci.numberPresentation) {
-                        ci.numberPresentation = conn.getNumberPresentation();
-                    }
-                } else {
-                    // No matching contact was found for this number.
-                    // Return a new CallerInfo based solely on the CNAP
-                    // information from the network.
-
-                    CallerInfo newCi = getCallerInfo(null, conn);
-
-                    // ...but copy over the (few) things we care about
-                    // from the original CallerInfo object:
-                    if (newCi != null) {
-                        newCi.setPhoneNumber(ci.getPhoneNumber()); // To get formatted phone number
-                        newCi.geoDescription = ci.geoDescription; // To get geo description string
-                        ci = newCi;
-                    }
-                }
-
-                if (DBG) log("==> Stashing CallerInfo " + ci + " into the connection...");
-                conn.setUserData(ci);
-            }
-        };
-
-
-    /**
-     * Returns a single "name" for the specified given a CallerInfo object.
-     * If the name is null, return defaultString as the default value, usually
-     * context.getString(R.string.unknown).
-     */
-    static String getCompactNameFromCallerInfo(CallerInfo ci, Context context) {
-        if (DBG) log("getCompactNameFromCallerInfo: info = " + ci);
-
-        String compactName = null;
-        if (ci != null) {
-            if (TextUtils.isEmpty(ci.getName())) {
-                // Perform any modifications for special CNAP cases to
-                // the phone number being displayed, if applicable.
-                compactName = modifyForSpecialCnapCases(context, ci, ci.getPhoneNumber(),
-                                                        ci.numberPresentation);
-            } else {
-                // Don't call modifyForSpecialCnapCases on regular name. See b/2160795.
-                compactName = ci.getName();
-            }
-        }
-
-        if ((compactName == null) || (TextUtils.isEmpty(compactName))) {
-            // If we're still null/empty here, then check if we have a presentation
-            // string that takes precedence that we could return, otherwise display
-            // "unknown" string.
-            if (ci != null && ci.numberPresentation == PhoneConstants.PRESENTATION_RESTRICTED) {
-                compactName = context.getString(R.string.private_num);
-            } else if (ci != null && ci.numberPresentation == PhoneConstants.PRESENTATION_PAYPHONE) {
-                compactName = context.getString(R.string.payphone);
-            } else {
-                compactName = context.getString(R.string.unknown);
-            }
-        }
-        if (VDBG) log("getCompactNameFromCallerInfo: compactName=" + compactName);
-        return compactName;
-    }
-
-    static boolean isInEmergencyCall(CallManager cm) {
-        Call fgCall = cm.getActiveFgCall();
-        // isIdle includes checks for the DISCONNECTING/DISCONNECTED state.
-        if(!fgCall.isIdle()) {
-            for (Connection cn : fgCall.getConnections()) {
-                if (PhoneNumberUtils.isLocalEmergencyNumber(PhoneGlobals.getInstance(),
-                        cn.getAddress())) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
 
     //
     // Misc UI policy helper functions
     //
 
     /**
-     * Based on the input CNAP number string,
-     * @return _RESTRICTED or _UNKNOWN for all the special CNAP strings.
-     * Otherwise, return CNAP_SPECIAL_CASE_NO.
-     */
-    private static int checkCnapSpecialCases(String n) {
-        if (n.equals("PRIVATE") ||
-                n.equals("P") ||
-                n.equals("RES")) {
-            if (DBG) log("checkCnapSpecialCases, PRIVATE string: " + n);
-            return PhoneConstants.PRESENTATION_RESTRICTED;
-        } else if (n.equals("UNAVAILABLE") ||
-                n.equals("UNKNOWN") ||
-                n.equals("UNA") ||
-                n.equals("U")) {
-            if (DBG) log("checkCnapSpecialCases, UNKNOWN string: " + n);
-            return PhoneConstants.PRESENTATION_UNKNOWN;
-        } else {
-            if (DBG) log("checkCnapSpecialCases, normal str. number: " + n);
-            return CNAP_SPECIAL_CASE_NO;
-        }
-    }
-
-    /**
-     * Handles certain "corner cases" for CNAP. When we receive weird phone numbers
-     * from the network to indicate different number presentations, convert them to
-     * expected number and presentation values within the CallerInfo object.
-     * @param number number we use to verify if we are in a corner case
-     * @param presentation presentation value used to verify if we are in a corner case
-     * @return the new String that should be used for the phone number
-     */
-    /* package */ static String modifyForSpecialCnapCases(Context context, CallerInfo ci,
-            String number, int presentation) {
-        // Obviously we return number if ci == null, but still return number if
-        // number == null, because in these cases the correct string will still be
-        // displayed/logged after this function returns based on the presentation value.
-        if (ci == null || number == null) return number;
-
-        if (DBG) {
-            log("modifyForSpecialCnapCases: initially, number="
-                    + toLogSafePhoneNumber(number)
-                    + ", presentation=" + presentation + " ci " + ci);
-        }
-
-        // "ABSENT NUMBER" is a possible value we could get from the network as the
-        // phone number, so if this happens, change it to "Unknown" in the CallerInfo
-        // and fix the presentation to be the same.
-        final String[] absentNumberValues =
-                context.getResources().getStringArray(R.array.absent_num);
-        if (Arrays.asList(absentNumberValues).contains(number)
-                && presentation == PhoneConstants.PRESENTATION_ALLOWED) {
-            number = context.getString(R.string.unknown);
-            ci.numberPresentation = PhoneConstants.PRESENTATION_UNKNOWN;
-        }
-
-        // Check for other special "corner cases" for CNAP and fix them similarly. Corner
-        // cases only apply if we received an allowed presentation from the network, so check
-        // if we think we have an allowed presentation, or if the CallerInfo presentation doesn't
-        // match the presentation passed in for verification (meaning we changed it previously
-        // because it's a corner case and we're being called from a different entry point).
-        if (ci.numberPresentation == PhoneConstants.PRESENTATION_ALLOWED
-                || (ci.numberPresentation != presentation
-                        && presentation == PhoneConstants.PRESENTATION_ALLOWED)) {
-            int cnapSpecialCase = checkCnapSpecialCases(number);
-            if (cnapSpecialCase != CNAP_SPECIAL_CASE_NO) {
-                // For all special strings, change number & numberPresentation.
-                if (cnapSpecialCase == PhoneConstants.PRESENTATION_RESTRICTED) {
-                    number = context.getString(R.string.private_num);
-                } else if (cnapSpecialCase == PhoneConstants.PRESENTATION_UNKNOWN) {
-                    number = context.getString(R.string.unknown);
-                }
-                if (DBG) {
-                    log("SpecialCnap: number=" + toLogSafePhoneNumber(number)
-                            + "; presentation now=" + cnapSpecialCase);
-                }
-                ci.numberPresentation = cnapSpecialCase;
-            }
-        }
-        if (DBG) {
-            log("modifyForSpecialCnapCases: returning number string="
-                    + toLogSafePhoneNumber(number));
-        }
-        return number;
-    }
-
-    //
-    // Support for 3rd party phone service providers.
-    //
-
-    /**
      * Check if a phone number can be route through a 3rd party
      * gateway. The number must be a global phone number in numerical
      * form (1-800-666-SEXY won't work).
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index d8d1717..428c006 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -16,10 +16,15 @@
 
 package com.android.phone;
 
+import android.content.Context;
 import android.os.Binder;
+import android.os.Build;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ShellCommand;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.emergency.EmergencyNumber;
 import android.util.Log;
@@ -29,6 +34,9 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeSet;
 
 /**
  * Takes actions based on the adb commands given by "adb shell cmd phone ...". Be careful, no
@@ -46,6 +54,7 @@
     private static final String IMS_SUBCOMMAND = "ims";
     private static final String NUMBER_VERIFICATION_SUBCOMMAND = "numverify";
     private static final String EMERGENCY_NUMBER_TEST_MODE = "emergency-number-test-mode";
+    private static final String CARRIER_CONFIG_SUBCOMMAND = "cc";
 
     private static final String IMS_SET_CARRIER_SERVICE = "set-ims-service";
     private static final String IMS_GET_CARRIER_SERVICE = "get-ims-service";
@@ -59,11 +68,60 @@
     private static final String NUMBER_VERIFICATION_OVERRIDE_PACKAGE = "override-package";
     private static final String NUMBER_VERIFICATION_FAKE_CALL = "fake-call";
 
+    private static final String CC_GET_VALUE = "get-value";
+    private static final String CC_SET_VALUE = "set-value";
+    private static final String CC_CLEAR_VALUES = "clear-values";
+
     // Take advantage of existing methods that already contain permissions checks when possible.
     private final ITelephony mInterface;
 
-    public TelephonyShellCommand(ITelephony binder) {
+    private SubscriptionManager mSubscriptionManager;
+    private CarrierConfigManager mCarrierConfigManager;
+
+    private enum CcType {
+        BOOLEAN, DOUBLE, DOUBLE_ARRAY, INT, INT_ARRAY, LONG, LONG_ARRAY, STRING,
+                STRING_ARRAY, UNKNOWN
+    }
+
+    // Maps carrier config keys to type. It is possible to infer the type for most carrier config
+    // keys by looking at the end of the string which usually tells the type.
+    // For instance: "xxxx_string", "xxxx_string_array", etc.
+    // The carrier config keys in this map does not follow this convention. It is therefore not
+    // possible to infer the type for these keys by looking at the string.
+    private static final Map<String, CcType> CC_TYPE_MAP = new HashMap<String, CcType>() {{
+            put(CarrierConfigManager.Gps.KEY_A_GLONASS_POS_PROTOCOL_SELECT_STRING, CcType.STRING);
+            put(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, CcType.STRING);
+            put(CarrierConfigManager.Gps.KEY_GPS_LOCK_STRING, CcType.STRING);
+            put(CarrierConfigManager.Gps.KEY_LPP_PROFILE_STRING, CcType.STRING);
+            put(CarrierConfigManager.Gps.KEY_NFW_PROXY_APPS_STRING, CcType.STRING);
+            put(CarrierConfigManager.Gps.KEY_SUPL_ES_STRING, CcType.STRING);
+            put(CarrierConfigManager.Gps.KEY_SUPL_HOST_STRING, CcType.STRING);
+            put(CarrierConfigManager.Gps.KEY_SUPL_MODE_STRING, CcType.STRING);
+            put(CarrierConfigManager.Gps.KEY_SUPL_PORT_STRING, CcType.STRING);
+            put(CarrierConfigManager.Gps.KEY_SUPL_VER_STRING, CcType.STRING);
+            put(CarrierConfigManager.Gps.KEY_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_STRING,
+                    CcType.STRING);
+            put(CarrierConfigManager.KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
+                    CcType.STRING_ARRAY);
+            put(CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
+                    CcType.STRING_ARRAY);
+            put(CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING, CcType.STRING);
+            put(CarrierConfigManager.KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING, CcType.STRING);
+            put(CarrierConfigManager.KEY_MMS_HTTP_PARAMS_STRING, CcType.STRING);
+            put(CarrierConfigManager.KEY_MMS_NAI_SUFFIX_STRING, CcType.STRING);
+            put(CarrierConfigManager.KEY_MMS_UA_PROF_TAG_NAME_STRING, CcType.STRING);
+            put(CarrierConfigManager.KEY_MMS_UA_PROF_URL_STRING, CcType.STRING);
+            put(CarrierConfigManager.KEY_MMS_USER_AGENT_STRING, CcType.STRING);
+            put(CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES, CcType.STRING_ARRAY);
+        }
+    };
+
+    public TelephonyShellCommand(ITelephony binder, Context context) {
         mInterface = binder;
+        mCarrierConfigManager =
+                (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        mSubscriptionManager = (SubscriptionManager)
+                context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
     }
 
     @Override
@@ -80,6 +138,9 @@
                 return handleNumberVerificationCommand();
             case EMERGENCY_NUMBER_TEST_MODE:
                 return handleEmergencyNumberTestModeCommand();
+            case CARRIER_CONFIG_SUBCOMMAND: {
+                return handleCcCommand();
+            }
             default: {
                 return handleDefaultCommands(cmd);
             }
@@ -96,8 +157,11 @@
         pw.println("    IMS Commands.");
         pw.println("  emergency-number-test-mode");
         pw.println("    Emergency Number Test Mode Commands.");
+        pw.println("  cc");
+        pw.println("    Carrier Config Commands.");
         onHelpIms();
         onHelpEmergencyNumber();
+        onHelpCc();
     }
 
     private void onHelpIms() {
@@ -152,6 +216,33 @@
         pw.println("      -p: get the full emergency number list in the test mode.");
     }
 
+    private void onHelpCc() {
+        PrintWriter pw = getOutPrintWriter();
+        pw.println("Carrier Config Commands:");
+        pw.println("  cc get-value [-s SLOT_ID] [KEY]");
+        pw.println("    Print carrier config values.");
+        pw.println("    Options are:");
+        pw.println("      -s: The SIM slot ID to read carrier config value for. If no option");
+        pw.println("          is specified, it will choose the default voice SIM slot.");
+        pw.println("    KEY: The key to the carrier config value to print. All values are printed");
+        pw.println("         if KEY is not specified.");
+        pw.println("  cc set-value [-s SLOT_ID] KEY [NEW_VALUE]");
+        pw.println("    Set carrier config KEY to NEW_VALUE.");
+        pw.println("    Options are:");
+        pw.println("      -s: The SIM slot ID to set carrier config value for. If no option");
+        pw.println("          is specified, it will choose the default voice SIM slot.");
+        pw.println("    NEW_VALUE specifies the new value for carrier config KEY. Null will be");
+        pw.println("      used if NEW_VALUE is not set. Strings should be encapsulated with");
+        pw.println("      quotation marks. Spaces needs to be escaped. Example: \"Hello\\ World\"");
+        pw.println("      Separate items in arrays with space . Example: \"item1\" \"item2\"");
+        pw.println("  cc clear-values [-s SLOT_ID]");
+        pw.println("    Clear all carrier override values that has previously been set");
+        pw.println("    with set-value");
+        pw.println("    Options are:");
+        pw.println("      -s: The SIM slot ID to clear carrier config values for. If no option");
+        pw.println("          is specified, it will choose the default voice SIM slot.");
+    }
+
     private int handleImsCommand() {
         String arg = getNextArg();
         if (arg == null) {
@@ -477,9 +568,486 @@
         return slotId;
     }
 
+    // Get the subId from argument SLOT_ID if it was provided. Otherwise use the default
+    // subscription.
+    private int getSubIdFromArgumentSlotId(String tag) {
+        PrintWriter errPw = getErrPrintWriter();
+        int subId = SubscriptionManager.getDefaultSubscriptionId();
+        String opt;
+
+        while ((opt = getNextOption()) != null) {
+            switch (opt) {
+                case "-s": {
+                    try {
+                        subId = slotStringToSubId(tag, getNextArgRequired());
+                    } catch (IllegalArgumentException e) {
+                        // Missing slot id
+                        errPw.println(tag + "SLOT_ID expected after -s.");
+                        return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+                    }
+                    break;
+                }
+                default: {
+                    errPw.println(tag + "Unknown option " + opt);
+                    return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+                }
+            }
+        }
+        return subId;
+    }
+
+    private int slotStringToSubId(String tag, String slotString) {
+        int slotId = -1;
+        try {
+            slotId = Integer.parseInt(slotString);
+        } catch (NumberFormatException e) {
+            getErrPrintWriter().println(tag + slotString + " is not a valid SLOT_ID.");
+            return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+        }
+
+        SubscriptionInfo subInfo =
+                mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(slotId);
+        if (subInfo == null) {
+            getErrPrintWriter().println(tag + "No subscription found in slot " + slotId + ".");
+            return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+        }
+        return subInfo.getSubscriptionId();
+    }
+
     private boolean checkShellUid() {
         // adb can run as root or as shell, depending on whether the device is rooted.
         return Binder.getCallingUid() == Process.SHELL_UID
                 || Binder.getCallingUid() == Process.ROOT_UID;
     }
+
+    private int handleCcCommand() {
+        // Verify that the user is allowed to run the command. Only allowed in rooted device in a
+        // non user build.
+        if (Binder.getCallingUid() != Process.ROOT_UID || Build.IS_USER) {
+            getErrPrintWriter().println("cc: Permission denied.");
+            return -1;
+        }
+
+        String arg = getNextArg();
+        if (arg == null) {
+            onHelpCc();
+            return 0;
+        }
+
+        switch (arg) {
+            case CC_GET_VALUE: {
+                return handleCcGetValue();
+            }
+            case CC_SET_VALUE: {
+                return handleCcSetValue();
+            }
+            case CC_CLEAR_VALUES: {
+                return handleCcClearValues();
+            }
+            default: {
+                getErrPrintWriter().println("cc: Unknown argument: " + arg);
+            }
+        }
+        return -1;
+    }
+
+    // cc get-value
+    private int handleCcGetValue() {
+        PrintWriter errPw = getErrPrintWriter();
+        String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_GET_VALUE + ": ";
+        String key = null;
+
+        // Get the subId from the SLOT_ID-argument.
+        int subId = getSubIdFromArgumentSlotId(tag);
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            errPw.println(tag + "No valid subscription found.");
+            return -1;
+        }
+
+        // Get bundle containing all carrier configuration values.
+        PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(subId);
+        if (bundle == null) {
+            errPw.println(tag + "No carrier config values found for subId " + subId + ".");
+            return -1;
+        }
+
+        // Get the key.
+        key = getNextArg();
+        if (key != null) {
+            // A key was provided. Verify if it is a valid key
+            if (!bundle.containsKey(key)) {
+                errPw.println(tag + key + " is not a valid key.");
+                return -1;
+            }
+
+            // Print the carrier config value for key.
+            getOutPrintWriter().println(ccValueToString(key, getType(tag, key, bundle), bundle));
+        } else {
+            // No key provided. Show all values.
+            // Iterate over a sorted list of all carrier config keys and print them.
+            TreeSet<String> sortedSet = new TreeSet<String>(bundle.keySet());
+            for (String k : sortedSet) {
+                getOutPrintWriter().println(ccValueToString(k, getType(tag, k, bundle), bundle));
+            }
+        }
+        return 0;
+    }
+
+    // cc set-value
+    private int handleCcSetValue() {
+        PrintWriter errPw = getErrPrintWriter();
+        String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUE + ": ";
+
+        // Get the subId from the SLOT_ID-argument.
+        int subId = getSubIdFromArgumentSlotId(tag);
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            errPw.println(tag + "No valid subscription found.");
+            return -1;
+        }
+
+        // Get bundle containing all current carrier configuration values.
+        PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(subId);
+        if (originalValues == null) {
+            errPw.println(tag + "No carrier config values found for subId " + subId + ".");
+            return -1;
+        }
+
+        // Get the key.
+        String key = getNextArg();
+        if (key == null || key.equals("")) {
+            errPw.println(tag + "KEY is missing");
+            return -1;
+        }
+
+        // Verify if the key is valid
+        if (!originalValues.containsKey(key)) {
+            errPw.println(tag + key + " is not a valid key.");
+            return -1;
+        }
+
+        // Remaining arguments is a list of new values. Add them all into an ArrayList.
+        ArrayList<String> valueList = new ArrayList<String>();
+        while (peekNextArg() != null) {
+            valueList.add(getNextArg());
+        }
+
+        // Find the type of the carrier config value
+        CcType type = getType(tag, key, originalValues);
+        if (type == CcType.UNKNOWN) {
+            errPw.println(tag + "ERROR: Not possible to override key with unknown type.");
+            return -1;
+        }
+
+        // Create an override bundle containing the key and value that should be overriden.
+        PersistableBundle overrideBundle = getOverrideBundle(tag, type, key, valueList);
+        if (overrideBundle == null) {
+            return -1;
+        }
+
+        // Override the value
+        mCarrierConfigManager.overrideConfig(subId, overrideBundle);
+
+        // Find bundle containing all new carrier configuration values after the override.
+        PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(subId);
+        if (newValues == null) {
+            errPw.println(tag + "No carrier config values found for subId " + subId + ".");
+            return -1;
+        }
+
+        // Print the original and new value.
+        String originalValueString = ccValueToString(key, type, originalValues);
+        String newValueString = ccValueToString(key, type, newValues);
+        getOutPrintWriter().println("Previous value: \n" + originalValueString);
+        getOutPrintWriter().println("New value: \n" + newValueString);
+
+        return 0;
+    }
+
+    // cc clear-values
+    private int handleCcClearValues() {
+        PrintWriter errPw = getErrPrintWriter();
+        String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_CLEAR_VALUES + ": ";
+
+        // Get the subId from the SLOT_ID-argument.
+        int subId = getSubIdFromArgumentSlotId(tag);
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            errPw.println(tag + "No valid subscription found.");
+            return -1;
+        }
+
+        // Clear all values that has previously been set.
+        mCarrierConfigManager.overrideConfig(subId, null);
+        getOutPrintWriter()
+                .println("All previously set carrier config override values has been cleared");
+        return 0;
+    }
+
+    private CcType getType(String tag, String key, PersistableBundle bundle) {
+        // Find the type by checking the type of the current value stored in the bundle.
+        Object value = bundle.get(key);
+
+        if (CC_TYPE_MAP.containsKey(key)) {
+            return CC_TYPE_MAP.get(key);
+        } else if (value != null) {
+            if (value instanceof Boolean) {
+                return CcType.BOOLEAN;
+            } else if (value instanceof Double) {
+                return CcType.DOUBLE;
+            } else if (value instanceof double[]) {
+                return CcType.DOUBLE_ARRAY;
+            } else if (value instanceof Integer) {
+                return CcType.INT;
+            } else if (value instanceof int[]) {
+                return CcType.INT_ARRAY;
+            } else if (value instanceof Long) {
+                return CcType.LONG;
+            } else if (value instanceof long[]) {
+                return CcType.LONG_ARRAY;
+            } else if (value instanceof String) {
+                return CcType.STRING;
+            } else if (value instanceof String[]) {
+                return CcType.STRING_ARRAY;
+            }
+        } else {
+            // Current value was null and can therefore not be used in order to find the type.
+            // Check the name of the key to infer the type. This check is not needed for primitive
+            // data types (boolean, double, int and long), since they can not be null.
+            if (key.endsWith("double_array")) {
+                return CcType.DOUBLE_ARRAY;
+            }
+            if (key.endsWith("int_array")) {
+                return CcType.INT_ARRAY;
+            }
+            if (key.endsWith("long_array")) {
+                return CcType.LONG_ARRAY;
+            }
+            if (key.endsWith("string")) {
+                return CcType.STRING;
+            }
+            if (key.endsWith("string_array") || key.endsWith("strings")) {
+                return CcType.STRING_ARRAY;
+            }
+        }
+
+        // Not possible to infer the type by looking at the current value or the key.
+        PrintWriter errPw = getErrPrintWriter();
+        errPw.println(tag + "ERROR: " + key + " has unknown type.");
+        return CcType.UNKNOWN;
+    }
+
+    private String ccValueToString(String key, CcType type, PersistableBundle bundle) {
+        String result;
+        StringBuilder valueString = new StringBuilder();
+        String typeString = type.toString();
+        Object value = bundle.get(key);
+
+        if (value == null) {
+            valueString.append("null");
+        } else {
+            switch (type) {
+                case DOUBLE_ARRAY: {
+                    // Format the string representation of the int array as value1 value2......
+                    double[] valueArray = (double[]) value;
+                    for (int i = 0; i < valueArray.length; i++) {
+                        if (i != 0) {
+                            valueString.append(" ");
+                        }
+                        valueString.append(valueArray[i]);
+                    }
+                    break;
+                }
+                case INT_ARRAY: {
+                    // Format the string representation of the int array as value1 value2......
+                    int[] valueArray = (int[]) value;
+                    for (int i = 0; i < valueArray.length; i++) {
+                        if (i != 0) {
+                            valueString.append(" ");
+                        }
+                        valueString.append(valueArray[i]);
+                    }
+                    break;
+                }
+                case LONG_ARRAY: {
+                    // Format the string representation of the int array as value1 value2......
+                    long[] valueArray = (long[]) value;
+                    for (int i = 0; i < valueArray.length; i++) {
+                        if (i != 0) {
+                            valueString.append(" ");
+                        }
+                        valueString.append(valueArray[i]);
+                    }
+                    break;
+                }
+                case STRING: {
+                    valueString.append("\"" + value.toString() + "\"");
+                    break;
+                }
+                case STRING_ARRAY: {
+                    // Format the string representation of the string array as "value1" "value2"....
+                    String[] valueArray = (String[]) value;
+                    for (int i = 0; i < valueArray.length; i++) {
+                        if (i != 0) {
+                            valueString.append(" ");
+                        }
+                        if (valueArray[i] != null) {
+                            valueString.append("\"" + valueArray[i] + "\"");
+                        } else {
+                            valueString.append("null");
+                        }
+                    }
+                    break;
+                }
+                default: {
+                    valueString.append(value.toString());
+                }
+            }
+        }
+        return String.format("%-70s %-15s %s", key, typeString, valueString);
+    }
+
+    private PersistableBundle getOverrideBundle(String tag, CcType type, String key,
+            ArrayList<String> valueList) {
+        PrintWriter errPw = getErrPrintWriter();
+        PersistableBundle bundle = new PersistableBundle();
+
+        // First verify that a valid number of values has been provided for the type.
+        switch (type) {
+            case BOOLEAN:
+            case DOUBLE:
+            case INT:
+            case LONG: {
+                if (valueList.size() != 1) {
+                    errPw.println(tag + "Expected 1 value for type " + type
+                            + ". Found: " + valueList.size());
+                    return null;
+                }
+                break;
+            }
+            case STRING: {
+                if (valueList.size() > 1) {
+                    errPw.println(tag + "Expected 0 or 1 values for type " + type
+                            + ". Found: " + valueList.size());
+                    return null;
+                }
+                break;
+            }
+        }
+
+        // Parse the value according to type and add it to the Bundle.
+        switch (type) {
+            case BOOLEAN: {
+                if ("true".equalsIgnoreCase(valueList.get(0))) {
+                    bundle.putBoolean(key, true);
+                } else if ("false".equalsIgnoreCase(valueList.get(0))) {
+                    bundle.putBoolean(key, false);
+                } else {
+                    errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
+                    return null;
+                }
+                break;
+            }
+            case DOUBLE: {
+                try {
+                    bundle.putDouble(key, Double.parseDouble(valueList.get(0)));
+                } catch (NumberFormatException nfe) {
+                    // Not a valid double
+                    errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
+                    return null;
+                }
+                break;
+            }
+            case DOUBLE_ARRAY: {
+                double[] valueDoubleArray = null;
+                if (valueList.size() > 0) {
+                    valueDoubleArray = new double[valueList.size()];
+                    for (int i = 0; i < valueList.size(); i++) {
+                        try {
+                            valueDoubleArray[i] = Double.parseDouble(valueList.get(i));
+                        } catch (NumberFormatException nfe) {
+                            // Not a valid double
+                            errPw.println(
+                                    tag + "Unable to parse " + valueList.get(i) + " as a double.");
+                            return null;
+                        }
+                    }
+                }
+                bundle.putDoubleArray(key, valueDoubleArray);
+                break;
+            }
+            case INT: {
+                try {
+                    bundle.putInt(key, Integer.parseInt(valueList.get(0)));
+                } catch (NumberFormatException nfe) {
+                    // Not a valid integer
+                    errPw.println(tag + "Unable to parse " + valueList.get(0) + " as an " + type);
+                    return null;
+                }
+                break;
+            }
+            case INT_ARRAY: {
+                int[] valueIntArray = null;
+                if (valueList.size() > 0) {
+                    valueIntArray = new int[valueList.size()];
+                    for (int i = 0; i < valueList.size(); i++) {
+                        try {
+                            valueIntArray[i] = Integer.parseInt(valueList.get(i));
+                        } catch (NumberFormatException nfe) {
+                            // Not a valid integer
+                            errPw.println(tag
+                                    + "Unable to parse " + valueList.get(i) + " as an integer.");
+                            return null;
+                        }
+                    }
+                }
+                bundle.putIntArray(key, valueIntArray);
+                break;
+            }
+            case LONG: {
+                try {
+                    bundle.putLong(key, Long.parseLong(valueList.get(0)));
+                } catch (NumberFormatException nfe) {
+                    // Not a valid long
+                    errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
+                    return null;
+                }
+                break;
+            }
+            case LONG_ARRAY: {
+                long[] valueLongArray = null;
+                if (valueList.size() > 0) {
+                    valueLongArray = new long[valueList.size()];
+                    for (int i = 0; i < valueList.size(); i++) {
+                        try {
+                            valueLongArray[i] = Long.parseLong(valueList.get(i));
+                        } catch (NumberFormatException nfe) {
+                            // Not a valid long
+                            errPw.println(
+                                    tag + "Unable to parse " + valueList.get(i) + " as a long");
+                            return null;
+                        }
+                    }
+                }
+                bundle.putLongArray(key, valueLongArray);
+                break;
+            }
+            case STRING: {
+                String value = null;
+                if (valueList.size() > 0) {
+                    value = valueList.get(0);
+                }
+                bundle.putString(key, value);
+                break;
+            }
+            case STRING_ARRAY: {
+                String[] valueStringArray = null;
+                if (valueList.size() > 0) {
+                    valueStringArray = new String[valueList.size()];
+                    valueList.toArray(valueStringArray);
+                }
+                bundle.putStringArray(key, valueStringArray);
+                break;
+            }
+        }
+        return bundle;
+    }
 }
diff --git a/src/com/android/phone/euicc/EuiccPublicActionUiDispatcherActivity.java b/src/com/android/phone/euicc/EuiccPublicActionUiDispatcherActivity.java
new file mode 100644
index 0000000..64a40b9
--- /dev/null
+++ b/src/com/android/phone/euicc/EuiccPublicActionUiDispatcherActivity.java
@@ -0,0 +1,52 @@
+/*
+ * 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.euicc;
+
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.service.euicc.EuiccService;
+import android.telephony.euicc.EuiccManager;
+import android.util.Log;
+
+/**
+ * Trampoline activity to forward public eUICC intents to the active UI implementation.
+ *
+ * <p>Unlike {@link EuiccUiDispatcherActivity}, this activity does not require any permissions to
+ * start.
+ */
+public class EuiccPublicActionUiDispatcherActivity extends EuiccUiDispatcherActivity {
+    private static final String TAG = "EuiccPublicActionUiDispatcherActivity";
+
+    @Override
+    @Nullable
+    protected Intent getEuiccUiIntent() {
+        String action = getIntent().getAction();
+
+        Intent intent = new Intent();
+        // Propagate the extras from the original Intent.
+        intent.putExtras(getIntent());
+        switch (action) {
+            case EuiccManager.ACTION_START_EUICC_ACTIVATION:
+                intent.setAction(EuiccService.ACTION_START_EUICC_ACTIVATION);
+                break;
+            default:
+                Log.w(TAG, "Unsupported action: " + action);
+                return null;
+        }
+
+        return intent;
+    }
+}
diff --git a/src/com/android/phone/otasp/OtaspActivationService.java b/src/com/android/phone/otasp/OtaspActivationService.java
index 7490880..6ed2ea8 100644
--- a/src/com/android/phone/otasp/OtaspActivationService.java
+++ b/src/com/android/phone/otasp/OtaspActivationService.java
@@ -150,11 +150,9 @@
         mPhone.registerForCdmaOtaStatusChange(mHandler, EVENT_CDMA_PROVISION_STATUS_UPDATE, null);
         mPhone.registerForPreciseCallStateChanged(mHandler, EVENT_CALL_STATE_CHANGED, null);
         logd("startNonInteractiveOtasp: placing call to '" + OTASP_NUMBER + "'...");
-        int callStatus = PhoneUtils.placeCall(this,
+        int callStatus = PhoneUtils.placeOtaspCall(this,
                 getPhone(),
-                OTASP_NUMBER,
-                null,   // contactRef
-                false); // isEmergencyCall
+                OTASP_NUMBER);
         if (callStatus == PhoneUtils.CALL_STATUS_DIALED) {
             if (DBG) logd("  ==> success return from placeCall(): callStatus = " + callStatus);
         } else {
diff --git a/src/com/android/phone/settings/PhoneAccountSettingsFragment.java b/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
index aa6b155..3811a77 100644
--- a/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
+++ b/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
@@ -101,7 +101,7 @@
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
-        mTelecomManager = TelecomManager.from(getActivity());
+        mTelecomManager = getActivity().getSystemService(TelecomManager.class);
         mTelephonyManager = TelephonyManager.from(getActivity());
         mSubscriptionManager = SubscriptionManager.from(getActivity());
     }
diff --git a/src/com/android/phone/vvm/VvmDumpHandler.java b/src/com/android/phone/vvm/VvmDumpHandler.java
index 866927e..82c5bb5 100644
--- a/src/com/android/phone/vvm/VvmDumpHandler.java
+++ b/src/com/android/phone/vvm/VvmDumpHandler.java
@@ -19,7 +19,7 @@
         indentedWriter.println("******* OmtpVvm *******");
         indentedWriter.println("======= Configs =======");
         indentedWriter.increaseIndent();
-        for (PhoneAccountHandle handle : TelecomManager.from(context)
+        for (PhoneAccountHandle handle : context.getSystemService(TelecomManager.class)
                 .getCallCapablePhoneAccounts()) {
             int subId = PhoneAccountHandleConverter.toSubId(handle);
             indentedWriter.println(
diff --git a/src/com/android/services/telephony/ConferenceParticipantConnection.java b/src/com/android/services/telephony/ConferenceParticipantConnection.java
index b1f1b23..ed92e7f 100644
--- a/src/com/android/services/telephony/ConferenceParticipantConnection.java
+++ b/src/com/android/services/telephony/ConferenceParticipantConnection.java
@@ -17,15 +17,13 @@
 package com.android.services.telephony;
 
 import android.net.Uri;
-import android.telecom.ConferenceParticipant;
 import android.telecom.Connection;
 import android.telecom.DisconnectCause;
-import android.telecom.PhoneAccount;
-import android.telephony.PhoneNumberUtils;
+import android.telephony.Rlog;
 import android.telephony.SubscriptionInfo;
 import android.text.TextUtils;
 
-import com.android.internal.annotations.VisibleForTesting;
+import com.android.ims.internal.ConferenceParticipant;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 
@@ -34,6 +32,8 @@
  */
 public class ConferenceParticipantConnection extends Connection {
 
+    private static final String LOG_TAG = "ConferenceParticipantConnection";
+
     /**
      * The user entity URI For the conference participant.
      */
@@ -88,7 +88,7 @@
      * @param newState The new state.
      */
     public void updateState(int newState) {
-        Log.v(this, "updateState endPoint: %s state: %s", Log.pii(mEndpoint),
+        Log.v(this, "updateState endPoint: %s state: %s", Rlog.pii(LOG_TAG, mEndpoint),
                 Connection.stateToString(newState));
         if (newState == getState()) {
             return;
@@ -203,13 +203,13 @@
         sb.append("[ConferenceParticipantConnection objId:");
         sb.append(System.identityHashCode(this));
         sb.append(" endPoint:");
-        sb.append(Log.pii(mEndpoint));
+        sb.append(Rlog.pii(LOG_TAG, mEndpoint));
         sb.append(" address:");
-        sb.append(Log.pii(getAddress()));
+        sb.append(Rlog.pii(LOG_TAG, getAddress()));
         sb.append(" addressPresentation:");
         sb.append(getAddressPresentation());
         sb.append(" parentConnection:");
-        sb.append(Log.pii(mParentConnection.getAddress()));
+        sb.append(Rlog.pii(LOG_TAG, mParentConnection.getAddress()));
         sb.append(" state:");
         sb.append(Connection.stateToString(getState()));
         sb.append(" connectTime:");
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index 4a5fb4a..9e32f00 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -117,6 +117,8 @@
     private static int toTelecomDisconnectCauseCode(int telephonyDisconnectCause) {
         switch (telephonyDisconnectCause) {
             case android.telephony.DisconnectCause.LOCAL:
+            //  The call was still disconnected locally, so this is not an error condition.
+            case android.telephony.DisconnectCause.OUTGOING_EMERGENCY_CALL_PLACED:
                 return DisconnectCause.LOCAL;
 
             case android.telephony.DisconnectCause.NORMAL:
@@ -797,6 +799,8 @@
                 break;
             case android.telephony.DisconnectCause.IMS_ACCESS_BLOCKED:
                 return DisconnectCause.REASON_IMS_ACCESS_BLOCKED;
+            case android.telephony.DisconnectCause.OUTGOING_EMERGENCY_CALL_PLACED:
+                return DisconnectCause.REASON_EMERGENCY_CALL_PLACED;
         }
 
         // If no specific code-mapping found, then fall back to using the reason.
diff --git a/src/com/android/services/telephony/HoldTracker.java b/src/com/android/services/telephony/HoldTracker.java
index 805802f..5032b41 100644
--- a/src/com/android/services/telephony/HoldTracker.java
+++ b/src/com/android/services/telephony/HoldTracker.java
@@ -16,7 +16,6 @@
 
 package com.android.services.telephony;
 
-import android.telecom.Log;
 import android.telecom.PhoneAccountHandle;
 
 import java.util.ArrayList;
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index 17549cf..b47adb2 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -21,19 +21,19 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.PersistableBundle;
-import android.telecom.ConferenceParticipant;
 import android.telecom.Connection;
 import android.telecom.Connection.VideoProvider;
 import android.telecom.DisconnectCause;
-import android.telecom.Log;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.StatusHints;
 import android.telecom.TelecomManager;
 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;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallStateException;
@@ -69,6 +69,8 @@
  */
 public class ImsConference extends TelephonyConferenceBase implements Holdable {
 
+    private static final String LOG_TAG = "ImsConference";
+
     /**
      * Abstracts out fetching a feature flag.  Makes testing easier.
      */
@@ -168,7 +170,7 @@
                         return;
                     }
 
-                    sendConnectionEvent(event, extras);
+                    sendConferenceEvent(event, extras);
                 }
 
                 @Override
@@ -328,15 +330,15 @@
 
         conferenceCapabilities = changeBitmask(conferenceCapabilities,
                     Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
-                    can(capabilities, Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL));
+                (capabilities & Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL) != 0);
 
         if (isVideoConferencingSupported) {
             conferenceCapabilities = changeBitmask(conferenceCapabilities,
                     Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
-                    can(capabilities, Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL));
+                    (capabilities & Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL) != 0);
             conferenceCapabilities = changeBitmask(conferenceCapabilities,
                     Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
-                    can(capabilities, Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO));
+                    (capabilities & Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO) != 0);
         } else {
             // If video conferencing is not supported, explicitly turn off the remote video
             // capability and the ability to upgrade to video.
@@ -349,7 +351,7 @@
 
         conferenceCapabilities = changeBitmask(conferenceCapabilities,
                 Connection.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
-                can(capabilities, Connection.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO));
+                (capabilities & Connection.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO) != 0);
 
         conferenceCapabilities = changeBitmask(conferenceCapabilities,
                 Connection.CAPABILITY_CAN_PAUSE_VIDEO,
@@ -368,15 +370,15 @@
     private int applyHostProperties(int conferenceProperties, int properties) {
         conferenceProperties = changeBitmask(conferenceProperties,
                 Connection.PROPERTY_HIGH_DEF_AUDIO,
-                can(properties, Connection.PROPERTY_HIGH_DEF_AUDIO));
+                (properties & Connection.PROPERTY_HIGH_DEF_AUDIO) != 0);
 
         conferenceProperties = changeBitmask(conferenceProperties,
                 Connection.PROPERTY_WIFI,
-                can(properties, Connection.PROPERTY_WIFI));
+                (properties & Connection.PROPERTY_WIFI) != 0);
 
         conferenceProperties = changeBitmask(conferenceProperties,
                 Connection.PROPERTY_IS_EXTERNAL_CALL,
-                can(properties, Connection.PROPERTY_IS_EXTERNAL_CALL));
+                (properties & Connection.PROPERTY_IS_EXTERNAL_CALL) != 0);
 
         conferenceProperties = changeBitmask(conferenceProperties,
                 Connection.PROPERTY_REMOTELY_HOSTED, !isConferenceHost());
@@ -602,7 +604,8 @@
      * that the conference is represented appropriately on Bluetooth devices.
      */
     private void updateManageConference() {
-        boolean couldManageConference = can(Connection.CAPABILITY_MANAGE_CONFERENCE);
+        boolean couldManageConference =
+                (getConnectionCapabilities() & Connection.CAPABILITY_MANAGE_CONFERENCE) != 0;
         boolean canManageConference = mFeatureFlagProxy.isUsingSinglePartyCallEmulation()
                 && mIsEmulatingSinglePartyCall
                 ? mConferenceParticipantConnections.size() > 1
@@ -822,8 +825,8 @@
                     if (!participantUserEntities.contains(entry.getKey())) {
                         ConferenceParticipantConnection participant = entry.getValue();
                         participant.setDisconnected(new DisconnectCause(DisconnectCause.CANCELED));
-                        mTelephonyConnectionService.removeConnection(participant);
                         removeTelephonyConnection(participant);
+                        participant.destroy();
                         entryIterator.remove();
                         oldParticipantsRemoved = true;
                     }
@@ -940,8 +943,8 @@
             // again anyways.
             entry.setDisconnected(new DisconnectCause(DisconnectCause.CANCELED,
                     DisconnectCause.REASON_EMULATING_SINGLE_CALL));
-            mTelephonyConnectionService.removeConnection(entry);
             removeTelephonyConnection(entry);
+            entry.destroy();
             valueIterator.remove();
         }
 
@@ -949,7 +952,8 @@
         setConferenceState(false);
 
         // Remove manage conference capability.
-        mCouldManageConference = can(Connection.CAPABILITY_MANAGE_CONFERENCE);
+        mCouldManageConference =
+                (getConnectionCapabilities() & Connection.CAPABILITY_MANAGE_CONFERENCE) != 0;
         int currentCapabilities = getConnectionCapabilities();
         currentCapabilities &= ~Connection.CAPABILITY_MANAGE_CONFERENCE;
         setConnectionCapabilities(currentCapabilities);
@@ -1009,7 +1013,7 @@
             mConferenceParticipantConnections.remove(new Pair<>(participant.getUserEntity(),
                     participant.getEndpoint()));
         }
-        mTelephonyConnectionService.removeConnection(participant);
+        participant.destroy();
     }
 
     /**
@@ -1025,7 +1029,6 @@
                 // Mark disconnect cause as cancelled to ensure that the call is not logged in the
                 // call log.
                 connection.setDisconnected(new DisconnectCause(DisconnectCause.CANCELED));
-                mTelephonyConnectionService.removeConnection(connection);
                 connection.destroy();
                 handleConnectionDestruction(connection);
             }
@@ -1086,7 +1089,7 @@
             boolean isHost = PhoneNumberUtils.compare(hostNumber, number);
 
             Log.v(this, "isParticipantHost(%s) : host: %s, participant %s", (isHost ? "Y" : "N"),
-                    Log.pii(hostNumber), Log.pii(number));
+                    Rlog.pii(LOG_TAG, hostNumber), Rlog.pii(LOG_TAG, number));
 
             if (isHost) {
                 return true;
@@ -1209,8 +1212,8 @@
      */
     private boolean isVideoCapable() {
         int capabilities = mConferenceHost.getConnectionCapabilities();
-        return can(capabilities, Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)
-                && can(capabilities, Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL);
+        return (capabilities & Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL) != 0
+                && (capabilities & Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL) != 0;
     }
 
     private void updateStatusHints() {
diff --git a/src/com/android/services/telephony/ImsConferenceController.java b/src/com/android/services/telephony/ImsConferenceController.java
index 315aaad..1e10055 100644
--- a/src/com/android/services/telephony/ImsConferenceController.java
+++ b/src/com/android/services/telephony/ImsConferenceController.java
@@ -22,6 +22,7 @@
 import android.telecom.ConnectionService;
 import android.telecom.DisconnectCause;
 import android.telecom.PhoneAccountHandle;
+import android.telephony.Rlog;
 
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
@@ -38,11 +39,13 @@
  * Manages conferences for IMS connections.
  */
 public class ImsConferenceController {
+    private static final String LOG_TAG = "ImsConferenceController";
 
     /**
      * Conference listener; used to receive notification when a conference has been disconnected.
      */
-    private final Conference.Listener mConferenceListener = new Conference.Listener() {
+    private final TelephonyConferenceBase.TelephonyConferenceListener mConferenceListener =
+            new TelephonyConferenceBase.TelephonyConferenceListener() {
         @Override
         public void onDestroyed(Conference conference) {
             if (Log.VERBOSE) {
@@ -69,13 +72,13 @@
 
         @Override
         public void onStateChanged(Connection c, int state) {
-            Log.v(this, "onStateChanged: %s", Log.pii(c.getAddress()));
+            Log.v(this, "onStateChanged: %s", Rlog.pii(LOG_TAG, c.getAddress()));
             recalculate();
         }
 
         @Override
         public void onDisconnected(Connection c, DisconnectCause disconnectCause) {
-            Log.v(this, "onDisconnected: %s", Log.pii(c.getAddress()));
+            Log.v(this, "onDisconnected: %s", Rlog.pii(LOG_TAG, c.getAddress()));
             recalculate();
         }
 
@@ -147,6 +150,7 @@
         mTelephonyConnections.add(connection);
         connection.addTelephonyConnectionListener(mTelephonyConnectionListener);
         recalculateConference();
+        recalculateConferenceable();
     }
 
     /**
@@ -379,7 +383,7 @@
         ImsConference conference = new ImsConference(mTelecomAccountRegistry, mConnectionService,
                 conferenceHostConnection, phoneAccountHandle, mFeatureFlagProxy);
         conference.setState(conferenceHostConnection.getState());
-        conference.addListener(mConferenceListener);
+        conference.addTelephonyConferenceListener(mConferenceListener);
         conference.updateConferenceParticipantsAfterCreation();
         mConnectionService.addConference(conference);
         conferenceHostConnection.setTelecomCallId(conference.getTelecomCallId());
diff --git a/src/com/android/services/telephony/Log.java b/src/com/android/services/telephony/Log.java
index 9941a59..57bf849 100644
--- a/src/com/android/services/telephony/Log.java
+++ b/src/com/android/services/telephony/Log.java
@@ -16,8 +16,6 @@
 
 package com.android.services.telephony;
 
-import android.content.Context;
-
 /**
  * Manages logging for the entire module.
  */
@@ -39,72 +37,80 @@
         return FORCE_LOGGING || android.util.Log.isLoggable(TAG, level);
     }
 
-    public static void initLogging(Context context) {
-        // Register Telephony with the Telecom Logger.
-        android.telecom.Log.setTag(TAG);
-        android.telecom.Log.setSessionContext(context);
-    }
-
     // Relay log messages to Telecom
     // TODO: Redo namespace of Telephony to use these methods directly.
 
     public static void d(String prefix, String format, Object... args) {
-        android.telecom.Log.d(prefix, format, args);
+        android.util.Log.d(TAG, (args == null || args.length == 0) ? format :
+                String.format(prefix + ": " + format, args));
     }
 
     public static void d(Object objectPrefix, String format, Object... args) {
-        android.telecom.Log.d(objectPrefix, format, args);
+        android.util.Log.d(TAG, (args == null || args.length == 0) ? format :
+                String.format(getPrefixFromObject(objectPrefix) + ": " + format, args));
     }
 
     public static void i(String prefix, String format, Object... args) {
-        android.telecom.Log.i(prefix, format, args);
+        android.util.Log.i(TAG, (args == null || args.length == 0) ? format :
+                String.format(prefix + ": " + format, args));
     }
 
     public static void i(Object objectPrefix, String format, Object... args) {
-        android.telecom.Log.i(objectPrefix, format, args);
+        android.util.Log.i(TAG, (args == null || args.length == 0) ? format :
+                String.format(getPrefixFromObject(objectPrefix) + ": " + format, args));
     }
 
     public static void v(String prefix, String format, Object... args) {
-        android.telecom.Log.v(prefix, format, args);
+        android.util.Log.v(TAG, (args == null || args.length == 0) ? format :
+                String.format(prefix + ": " + format, args));
     }
 
     public static void v(Object objectPrefix, String format, Object... args) {
-        android.telecom.Log.v(objectPrefix, format, args);
+        android.util.Log.v(TAG, (args == null || args.length == 0) ? format :
+                String.format(getPrefixFromObject(objectPrefix) + ": " + format, args));
     }
 
     public static void w(String prefix, String format, Object... args) {
-        android.telecom.Log.w(prefix, format, args);
+        android.util.Log.w(TAG, (args == null || args.length == 0) ? format :
+                String.format(prefix + ": " + format, args));
     }
 
     public static void w(Object objectPrefix, String format, Object... args) {
-        android.telecom.Log.w(objectPrefix, format, args);
+        android.util.Log.w(TAG, (args == null || args.length == 0) ? format :
+                String.format(getPrefixFromObject(objectPrefix) + ": " + format, args));
     }
 
     public static void e(String prefix, Throwable tr, String format, Object... args) {
-        android.telecom.Log.e(prefix, tr, format, args);
+        android.util.Log.e(TAG, (args == null || args.length == 0) ? format :
+                String.format(prefix + ": " + format, args), tr);
     }
 
     public static void e(Object objectPrefix, Throwable tr, String format, Object... args) {
-        android.telecom.Log.e(objectPrefix, tr, format, args);
+        android.util.Log.e(TAG, (args == null || args.length == 0) ? format :
+                String.format(getPrefixFromObject(objectPrefix) + ": " + format, args), tr);
     }
 
     public static void wtf(String prefix, Throwable tr, String format, Object... args) {
-        android.telecom.Log.wtf(prefix, tr, format, args);
+        android.util.Log.wtf(TAG, (args == null || args.length == 0) ? format :
+                String.format(prefix + ": " + format, args), tr);
     }
 
     public static void wtf(Object objectPrefix, Throwable tr, String format, Object... args) {
-        android.telecom.Log.wtf(objectPrefix, tr, format, args);
+        android.util.Log.wtf(TAG, (args == null || args.length == 0) ? format :
+                String.format(getPrefixFromObject(objectPrefix) + ": " + format, args), tr);
     }
 
     public static void wtf(String prefix, String format, Object... args) {
-        android.telecom.Log.wtf(prefix, format, args);
+        android.util.Log.wtf(TAG, (args == null || args.length == 0) ? format :
+                String.format(prefix + ": " + format, args));
     }
 
     public static void wtf(Object objectPrefix, String format, Object... args) {
-        android.telecom.Log.wtf(objectPrefix, format, args);
+        android.util.Log.wtf(TAG, (args == null || args.length == 0) ? format :
+                String.format(getPrefixFromObject(objectPrefix) + ": " + format, args));
     }
 
-    public static String pii(Object pii) {
-        return android.telecom.Log.pii(pii);
+    private static String getPrefixFromObject(Object obj) {
+        return obj == null ? "<null>" : obj.getClass().getSimpleName();
     }
 }
diff --git a/src/com/android/services/telephony/PstnIncomingCallNotifier.java b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
index a2ced9e..f397dce 100644
--- a/src/com/android/services/telephony/PstnIncomingCallNotifier.java
+++ b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
@@ -25,6 +25,7 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
+import android.telephony.Rlog;
 import android.text.TextUtils;
 
 import com.android.internal.telephony.Call;
@@ -49,6 +50,8 @@
  * occurence. One instance of these exists for each of the telephony-based call services.
  */
 final class PstnIncomingCallNotifier {
+    private static final String LOG_TAG = "PstnIncomingCallNotifier";
+
     /** New ringing connection event code. */
     private static final int EVENT_NEW_RINGING_CONNECTION = 100;
     private static final int EVENT_CDMA_CALL_WAITING = 101;
@@ -181,7 +184,7 @@
                     // Presentation of the number is allowed, so we ensure the number matches the
                     // one in the call waiting information.
                     Log.i(this, "handleCdmaCallWaiting: inform telecom of waiting call; "
-                            + "number = %s", Log.pii(number));
+                            + "number = %s", Rlog.pii(LOG_TAG, number));
                     sendIncomingCallIntent(connection);
                 } else {
                     Log.w(this, "handleCdmaCallWaiting: presentation or number do not match, not"
@@ -248,7 +251,8 @@
                     // connection already disconnected. Do nothing
                 }
             } else {
-                TelecomManager.from(mPhone.getContext()).addNewUnknownCall(handle, extras);
+                TelecomManager tm = mPhone.getContext().getSystemService(TelecomManager.class);
+                tm.addNewUnknownCall(handle, extras);
             }
         } else {
             Log.i(this, "swapped an old connection, new one is: %s", connection);
@@ -283,7 +287,8 @@
                 // connection already disconnected. Do nothing
             }
         } else {
-            TelecomManager.from(mPhone.getContext()).addNewIncomingCall(handle, extras);
+            TelecomManager tm = mPhone.getContext().getSystemService(TelecomManager.class);
+            tm.addNewIncomingCall(handle, extras);
         }
     }
 
diff --git a/src/com/android/services/telephony/RadioOnHelper.java b/src/com/android/services/telephony/RadioOnHelper.java
index 741a6c5..981dc96 100644
--- a/src/com/android/services/telephony/RadioOnHelper.java
+++ b/src/com/android/services/telephony/RadioOnHelper.java
@@ -49,13 +49,19 @@
     }
 
     private void setupListeners() {
-        if (mListeners != null) {
-            return;
+        if (mListeners == null) {
+            mListeners = new ArrayList<>(2);
         }
-        mListeners = new ArrayList<>(2);
-        for (int i = 0; i < TelephonyManager.getDefault().getSupportedModemCount(); i++) {
+        int activeModems = TelephonyManager.from(mContext).getActiveModemCount();
+        // Add new listeners if active modem count increased.
+        while (mListeners.size() < activeModems) {
             mListeners.add(new RadioOnStateListener());
         }
+        // Clean up listeners if active modem count decreased.
+        while (mListeners.size() > activeModems) {
+            mListeners.get(mListeners.size() - 1).cleanup();
+            mListeners.remove(mListeners.size() - 1);
+        }
     }
     /**
      * Starts the "turn on radio" sequence. This is the (single) external API of the
@@ -76,7 +82,7 @@
         mCallback = callback;
         mInProgressListeners.clear();
         mIsRadioOnCallingEnabled = false;
-        for (int i = 0; i < TelephonyManager.getDefault().getSupportedModemCount(); i++) {
+        for (int i = 0; i < TelephonyManager.from(mContext).getActiveModemCount(); i++) {
             Phone phone = PhoneFactory.getPhone(i);
             if (phone == null) {
                 continue;
diff --git a/src/com/android/services/telephony/RadioOnStateListener.java b/src/com/android/services/telephony/RadioOnStateListener.java
index 729f6a9..52bd9cf 100644
--- a/src/com/android/services/telephony/RadioOnStateListener.java
+++ b/src/com/android/services/telephony/RadioOnStateListener.java
@@ -231,7 +231,7 @@
      * Note we don't call this method simply after a successful call to placeCall(), since it's
      * still possible the call will disconnect very quickly with an OUT_OF_SERVICE error.
      */
-    private void cleanup() {
+    public void cleanup() {
         Log.d(this, "cleanup()");
 
         // This will send a failure call back if callback has yet to be invoked.  If the callback
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 2e923ec..092e08b 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -42,6 +42,7 @@
 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;
@@ -72,6 +73,7 @@
  */
 public class TelecomAccountRegistry {
     private static final boolean DBG = false; /* STOP SHIP if true */
+    private static final String LOG_TAG = "TelecomAccountRegistry";
 
     // This icon is the one that is used when the Slot ID that we have for a particular SIM
     // is not supported, i.e. SubscriptionManager.INVALID_SLOT_ID or the 5th SIM in a phone.
@@ -286,7 +288,7 @@
                 mIsRttCapable = false;
             }
 
-            mIsVideoCapable = mPhone.isVideoEnabled() && !mIsRttCapable;
+            mIsVideoCapable = mPhone.isVideoEnabled();
             boolean isVideoEnabledByPlatform = ImsManager.getInstance(mPhone.getContext(),
                     mPhone.getPhoneId()).isVtEnabledByPlatform();
 
@@ -390,7 +392,7 @@
             }
             if(isMergedSim) {
                 groupId = GROUP_PREFIX + line1Number;
-                Log.i(this, "Adding Merged Account with group: " + Log.pii(groupId));
+                Log.i(this, "Adding Merged Account with group: " + Rlog.pii(LOG_TAG, groupId));
             }
 
             PhoneAccount account = PhoneAccount.builder(phoneAccountHandle, label)
@@ -876,7 +878,7 @@
 
     TelecomAccountRegistry(Context context) {
         mContext = context;
-        mTelecomManager = TelecomManager.from(context);
+        mTelecomManager = context.getSystemService(TelecomManager.class);
         mTelephonyManager = TelephonyManager.from(context);
         mSubscriptionManager = SubscriptionManager.from(context);
     }
@@ -1148,7 +1150,7 @@
                 R.bool.config_emergency_account_emergency_calls_only);
         List<PhoneAccountHandle> accountHandles = emergencyCallsOnlyEmergencyAccount
                 ? mTelecomManager.getAllPhoneAccountHandles()
-                : mTelecomManager.getCallCapablePhoneAccounts(true /* includeDisabled */);
+                : mTelecomManager.getCallCapablePhoneAccounts();
 
         for (PhoneAccountHandle handle : accountHandles) {
             if (telephonyComponentName.equals(handle.getComponentName()) &&
diff --git a/src/com/android/services/telephony/TelephonyConferenceBase.java b/src/com/android/services/telephony/TelephonyConferenceBase.java
index 31d0f56..a8bbf64 100644
--- a/src/com/android/services/telephony/TelephonyConferenceBase.java
+++ b/src/com/android/services/telephony/TelephonyConferenceBase.java
@@ -20,6 +20,8 @@
 import android.telecom.Conference;
 import android.telecom.Connection;
 import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.telephony.ServiceState;
 
 import java.util.Collections;
 import java.util.Iterator;
@@ -32,6 +34,8 @@
  * all of these conferences use.
  */
 public class TelephonyConferenceBase extends Conference {
+    private static final String TAG = "TelephonyConferenceBase";
+
     /**
      * Listener for conference events.
      */
@@ -40,7 +44,13 @@
          * Listener called when a connection is added or removed from a conference.
          * @param connection The connection.
          */
-        public void onConferenceMembershipChanged(Connection connection) {};
+        public void onConferenceMembershipChanged(Connection connection) {}
+
+        /**
+         * Listener called when a conference is destroyed.
+         * @param conference The conference.
+         */
+        public void onDestroyed(Conference conference) {}
     }
 
     private final Set<TelephonyConferenceListener> mListeners = Collections.newSetFromMap(
@@ -50,7 +60,7 @@
      * Adds a listener to this conference.
      * @param listener The listener.
      */
-    public void addListener(@NonNull TelephonyConferenceListener listener) {
+    public void addTelephonyConferenceListener(@NonNull TelephonyConferenceListener listener) {
         mListeners.add(listener);
     }
 
@@ -58,7 +68,7 @@
      * Removes a listener from this conference.
      * @param listener The listener.
      */
-    public void removeListener(@NonNull TelephonyConferenceListener listener) {
+    public void removeTelephonyConferenceListener(@NonNull TelephonyConferenceListener listener) {
         mListeners.remove(listener);
     }
 
@@ -114,6 +124,46 @@
             removeTelephonyConnection(connectionIterator.next());
         }
         destroy();
+        notifyDestroyed();
+    }
+
+    /**
+     * Updates RIL voice radio technology used for current conference after its creation.
+     */
+    public void updateCallRadioTechAfterCreation() {
+        final Connection primaryConnection = getPrimaryConnection();
+        if (primaryConnection != null && primaryConnection instanceof TelephonyConnection) {
+            TelephonyConnection telephonyConnection = (TelephonyConnection) primaryConnection;
+            putExtra(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
+                    ServiceState.rilRadioTechnologyToNetworkType(
+                            telephonyConnection.getCallRadioTech()));
+        } else {
+            Log.w(TAG, "No primary connection found while updateCallRadioTechAfterCreation");
+        }
+    }
+
+    /**
+     * Removes the specified capability from the set of capabilities of this {@code Conference}.
+     *
+     * @param capability The capability to remove from the set.
+     */
+    public void removeCapability(int capability) {
+        int newCapabilities = getConnectionCapabilities();
+        newCapabilities &= ~capability;
+
+        setConnectionCapabilities(newCapabilities);
+    }
+
+    /**
+     * Adds the specified capability to the set of capabilities of this {@code Conference}.
+     *
+     * @param capability The capability to add to the set.
+     */
+    public void addCapability(int capability) {
+        int newCapabilities = getConnectionCapabilities();
+        newCapabilities |= capability;
+
+        setConnectionCapabilities(newCapabilities);
     }
 
     /**
@@ -126,4 +176,13 @@
             listener.onConferenceMembershipChanged(connection);
         }
     }
+
+    /**
+     * Notifies {@link TelephonyConferenceListener}s of a conference being destroyed
+     */
+    private void notifyDestroyed() {
+        for (TelephonyConferenceListener listener : mListeners) {
+            listener.onDestroyed(this);
+        }
+    }
 }
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 3e9cab9..fc9e255 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -29,7 +29,6 @@
 import android.os.PersistableBundle;
 import android.telecom.CallAudioState;
 import android.telecom.Conference;
-import android.telecom.ConferenceParticipant;
 import android.telecom.Connection;
 import android.telecom.ConnectionService;
 import android.telecom.PhoneAccount;
@@ -40,6 +39,7 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.telephony.ims.ImsCallProfile;
@@ -47,6 +47,7 @@
 import android.util.Pair;
 
 import com.android.ims.ImsCall;
+import com.android.ims.internal.ConferenceParticipant;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallFailCause;
@@ -78,6 +79,8 @@
  * Base class for CDMA and GSM connections.
  */
 abstract class TelephonyConnection extends Connection implements Holdable {
+    private static final String LOG_TAG = "TelephonyConnection";
+
     private static final int MSG_PRECISE_CALL_STATE_CHANGED = 1;
     private static final int MSG_RINGBACK_TONE = 2;
     private static final int MSG_HANDOVER_STATE_CHANGED = 3;
@@ -759,6 +762,11 @@
     private boolean mShowPreciseFailedCause;
 
     /**
+     * Provides a DisconnectCause associated with a hang up request.
+     */
+    private int mHangupDisconnectCause = DisconnectCause.NOT_VALID;
+
+    /**
      * Listeners to our TelephonyConnection specific callbacks
      */
     private final Set<TelephonyConnectionListener> mTelephonyListeners = Collections.newSetFromMap(
@@ -1477,6 +1485,7 @@
 
     protected void hangup(int telephonyDisconnectCode) {
         if (mOriginalConnection != null) {
+            mHangupDisconnectCause = telephonyDisconnectCode;
             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
@@ -1608,8 +1617,8 @@
                         for (String key : extras.keySet()) {
                             Object value = extras.get(key);
                             if (value instanceof String) {
-                                Log.d(this, "updateExtras Key=" + Log.pii(key) +
-                                             " value=" + Log.pii((String)value));
+                                Log.d(this, "updateExtras Key=" + Rlog.pii(LOG_TAG, key)
+                                        + " value=" + Rlog.pii(LOG_TAG, value));
                             }
                         }
                     }
@@ -1632,7 +1641,7 @@
                     Log.d(this, "Extras update not required");
                 }
             } else {
-                Log.d(this, "updateExtras extras: " + Log.pii(extras));
+                Log.d(this, "updateExtras extras: " + Rlog.pii(LOG_TAG, extras));
             }
         }
     }
@@ -1729,9 +1738,16 @@
                             preciseDisconnectCause =
                                     mOriginalConnection.getPreciseDisconnectCause();
                         }
+                        int disconnectCause = mOriginalConnection.getDisconnectCause();
+                        if ((mHangupDisconnectCause != DisconnectCause.NOT_VALID)
+                                && (mHangupDisconnectCause != disconnectCause)) {
+                            Log.i(LOG_TAG, "setDisconnected: override cause: " + disconnectCause
+                                    + " -> " + mHangupDisconnectCause);
+                            disconnectCause = mHangupDisconnectCause;
+                        }
                         setTelephonyConnectionDisconnected(
                                 DisconnectCauseUtil.toTelecomDisconnectCause(
-                                        mOriginalConnection.getDisconnectCause(),
+                                        disconnectCause,
                                         preciseDisconnectCause,
                                         mOriginalConnection.getVendorDisconnectCause(),
                                         getPhone().getPhoneId()));
@@ -2392,7 +2408,7 @@
         sb.append(" properties:");
         sb.append(propertiesToString(getConnectionProperties()));
         sb.append(" address:");
-        sb.append(Log.pii(getAddress()));
+        sb.append(Rlog.pii(LOG_TAG, getAddress()));
         sb.append(" originalConnection:");
         sb.append(mOriginalConnection);
         sb.append(" partOfConf:");
@@ -2556,6 +2572,50 @@
     }
 
     /**
+     * Sets RIL voice radio technology used for current connection.
+     * <p>
+     * This property is set by the Telephony {@link ConnectionService}.
+     *
+     * @param vrat the RIL Voice Radio Technology used for current connection,
+     *             see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
+     */
+    public final void setCallRadioTech(@ServiceState.RilRadioTechnology int vrat) {
+        Bundle extras = getExtras();
+        if (extras == null) {
+            extras = new Bundle();
+        }
+        extras.putInt(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
+                ServiceState.rilRadioTechnologyToNetworkType(vrat));
+        putExtras(extras);
+        // Propagates the call radio technology to its parent {@link android.telecom.Conference}
+        // This action only covers non-IMS CS conference calls.
+        // For IMS PS call conference call, it can be updated via its host connection
+        // {@link #Listener.onExtrasChanged} event.
+        if (getConference() != null) {
+            getConference().putExtra(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
+                    ServiceState.rilRadioTechnologyToNetworkType(vrat));
+        }
+    }
+
+    /**
+     * Returns RIL voice radio technology used for current connection.
+     * <p>
+     * Used by the Telephony {@link ConnectionService}.
+     *
+     * @return the RIL voice radio technology used for current connection,
+     *         see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
+     */
+    public final @ServiceState.RilRadioTechnology int getCallRadioTech() {
+        int voiceNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+        Bundle extras = getExtras();
+        if (extras != null) {
+            voiceNetworkType = extras.getInt(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
+                    TelephonyManager.NETWORK_TYPE_UNKNOWN);
+        }
+        return ServiceState.networkTypeToRilRadioTechnology(voiceNetworkType);
+    }
+
+    /**
      * Notifies {@link TelephonyConnectionListener}s of a change to conference participant data
      * received via the {@link ImsConference} (i.e. conference event package).
      *
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 7b55bfc..61e06e9 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -110,10 +110,6 @@
             TelephonyConnectionService.this.addTelephonyConference(mImsConference);
         }
         @Override
-        public void removeConnection(Connection connection) {
-            TelephonyConnectionService.this.removeConnection(connection);
-        }
-        @Override
         public void addExistingConnection(PhoneAccountHandle phoneAccountHandle,
                                           Connection connection) {
             TelephonyConnectionService.this
@@ -129,11 +125,6 @@
         public void addConnectionToConferenceController(TelephonyConnection connection) {
             TelephonyConnectionService.this.addConnectionToConferenceController(connection);
         }
-
-        @Override
-        public void onConferenceMembershipChanged(Connection connection) {
-            mHoldTracker.updateHoldCapability(connection.getPhoneAccountHandle());
-        }
     };
 
     private final BroadcastReceiver mTtyBroadcastReceiver = new BroadcastReceiver() {
@@ -329,7 +320,6 @@
     @Override
     public void onCreate() {
         super.onCreate();
-        Log.initLogging(this);
         setTelephonyManagerProxy(new TelephonyManagerProxyImpl(getApplicationContext()));
         mExpectedComponentName = new ComponentName(this, this.getClass());
         mEmergencyTonePlayer = new EmergencyTonePlayer(this);
@@ -824,7 +814,7 @@
 
         final TelephonyConnection connection =
                 createConnectionFor(phone, null, true /* isOutgoing */, request.getAccountHandle(),
-                        request.getTelecomCallId(), request.getAddress(), request.getVideoState());
+                        request.getTelecomCallId());
         if (connection == null) {
             return Connection.createFailedConnection(
                     DisconnectCauseUtil.toTelecomDisconnectCause(
@@ -883,15 +873,9 @@
             return Connection.createCanceledConnection();
         }
 
-        // We should rely on the originalConnection to get the video state.  The request coming
-        // from Telecom does not know the video state of the incoming call.
-        int videoState = originalConnection != null ? originalConnection.getVideoState() :
-                VideoProfile.STATE_AUDIO_ONLY;
-
         TelephonyConnection connection =
                 createConnectionFor(phone, originalConnection, false /* isOutgoing */,
-                        request.getAccountHandle(), request.getTelecomCallId(),
-                        request.getAddress(), videoState);
+                        request.getAccountHandle(), request.getTelecomCallId());
         handleIncomingRtt(request, originalConnection);
         if (connection == null) {
             return Connection.createCanceledConnection();
@@ -948,6 +932,61 @@
     }
 
     @Override
+    public void onCreateIncomingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount,
+            ConnectionRequest request) {
+        Log.i(this, "onCreateIncomingConnectionFailed, request: " + request);
+        // If there is an incoming emergency CDMA Call (while the phone is in ECBM w/ No SIM),
+        // make sure the PhoneAccount lookup retrieves the default Emergency Phone.
+        PhoneAccountHandle accountHandle = request.getAccountHandle();
+        boolean isEmergency = false;
+        if (accountHandle != null && PhoneUtils.EMERGENCY_ACCOUNT_HANDLE_ID.equals(
+                accountHandle.getId())) {
+            Log.w(this, "onCreateIncomingConnectionFailed:Emergency call failed... ");
+            isEmergency = true;
+        }
+        Phone phone = getPhoneForAccount(accountHandle, isEmergency,
+                /* Note: when not an emergency, handle can be null for unknown callers */
+                request.getAddress() == null ? null : request.getAddress().getSchemeSpecificPart());
+        if (phone == null) {
+            Log.w(this, "onCreateIncomingConnectionFailed: can not find corresponding phone.");
+            return;
+        }
+
+        Call call = phone.getRingingCall();
+        if (!call.getState().isRinging()) {
+            Log.w(this, "onCreateIncomingConnectionFailed, no ringing call found for failed call");
+            return;
+        }
+
+        com.android.internal.telephony.Connection originalConnection =
+                call.getState() == Call.State.WAITING
+                        ? call.getLatestConnection() : call.getEarliestConnection();
+        TelephonyConnection knownConnection =
+                getConnectionForOriginalConnection(originalConnection);
+        if (knownConnection != null) {
+            Log.w(this, "onCreateIncomingConnectionFailed, original connection already registered."
+                    + " Hanging it up.");
+            knownConnection.onAbort();
+            return;
+        }
+
+        TelephonyConnection connection =
+                createConnectionFor(phone, originalConnection, false /* isOutgoing */,
+                        request.getAccountHandle(), request.getTelecomCallId());
+        if (connection == null) {
+            Log.w(this, "onCreateIncomingConnectionFailed, TelephonyConnection created as null, "
+                    + "ignoring.");
+            return;
+        }
+
+        // We have to do all of this work because in some cases, hanging up the call maps to
+        // different underlying signaling (CDMA), which is already encapsulated in
+        // TelephonyConnection.
+        connection.onReject();
+        connection.close();
+    }
+
+    @Override
     public void triggerConferenceRecalculate() {
         if (mTelephonyConferenceController.shouldRecalculate()) {
             mTelephonyConferenceController.recalculate();
@@ -1046,8 +1085,8 @@
         TelephonyConnection connection =
                 createConnectionFor(phone, unknownConnection,
                         !unknownConnection.isIncoming() /* isOutgoing */,
-                        request.getAccountHandle(), request.getTelecomCallId(),
-                        request.getAddress(), videoState);
+                        request.getAccountHandle(), request.getTelecomCallId()
+                );
 
         if (connection == null) {
             return Connection.createCanceledConnection();
@@ -1250,6 +1289,19 @@
                         phone.getEmergencyNumberTracker().getEmergencyNumber(number);
                 if (emergencyNumber != null) {
                     phone.notifyOutgoingEmergencyCall(emergencyNumber);
+                    // If we do not support holding ongoing calls for an outgoing emergency call,
+                    // disconnect the ongoing calls.
+                    if (!shouldHoldForEmergencyCall(phone) && !getAllConnections().isEmpty()) {
+                        for (Connection c : getAllConnections()) {
+                            if (!c.equals(connection)
+                                    && c.getState() != Connection.STATE_DISCONNECTED
+                                    && c instanceof TelephonyConnection) {
+                                ((TelephonyConnection) c).hangup(
+                                        android.telephony.DisconnectCause
+                                                .OUTGOING_EMERGENCY_CALL_PLACED);
+                            }
+                        }
+                    }
                 }
                 originalConnection = phone.dial(number, new ImsPhone.ImsDialArgs.Builder()
                         .setVideoState(videoState)
@@ -1316,14 +1368,24 @@
         }
     }
 
+    private boolean shouldHoldForEmergencyCall(Phone phone) {
+        CarrierConfigManager cfgManager = (CarrierConfigManager)
+                phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        if (cfgManager == null) {
+            // For some reason CarrierConfigManager is unavailable, return default
+            Log.w(this, "shouldHoldForEmergencyCall: couldn't get CarrierConfigManager");
+            return true;
+        }
+        return cfgManager.getConfigForSubId(phone.getSubId()).getBoolean(
+                CarrierConfigManager.KEY_ALLOW_HOLD_CALL_DURING_EMERGENCY_BOOL, true);
+    }
+
     private TelephonyConnection createConnectionFor(
             Phone phone,
             com.android.internal.telephony.Connection originalConnection,
             boolean isOutgoing,
             PhoneAccountHandle phoneAccountHandle,
-            String telecomCallId,
-            Uri address,
-            int videoState) {
+            String telecomCallId) {
         TelephonyConnection returnConnection = null;
         int phoneType = phone.getPhoneType();
         if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
@@ -1352,15 +1414,20 @@
 
     private boolean isOriginalConnectionKnown(
             com.android.internal.telephony.Connection originalConnection) {
+        return (getConnectionForOriginalConnection(originalConnection) != null);
+    }
+
+    private TelephonyConnection getConnectionForOriginalConnection(
+            com.android.internal.telephony.Connection originalConnection) {
         for (Connection connection : getAllConnections()) {
             if (connection instanceof TelephonyConnection) {
                 TelephonyConnection telephonyConnection = (TelephonyConnection) connection;
                 if (telephonyConnection.getOriginalConnection() == originalConnection) {
-                    return true;
+                    return telephonyConnection;
                 }
             }
         }
-        return false;
+        return null;
     }
 
     /**
@@ -1784,7 +1851,8 @@
 
                     // If the CDMA conference has not been merged, add-call will not work, so fail
                     // this request to add a call.
-                    if (cdmaConf.can(Connection.CAPABILITY_MERGE_CONFERENCE)) {
+                    if ((cdmaConf.getConnectionCapabilities()
+                            & Connection.CAPABILITY_MERGE_CONFERENCE) != 0) {
                         return Connection.createFailedConnection(new DisconnectCause(
                                     DisconnectCause.RESTRICTED,
                                     null,
@@ -1861,6 +1929,6 @@
      */
     public void addTelephonyConference(@NonNull TelephonyConferenceBase conference) {
         addConference(conference);
-        conference.addListener(mTelephonyConferenceListener);
+        conference.addTelephonyConferenceListener(mTelephonyConferenceListener);
     }
 }
diff --git a/src/com/android/services/telephony/TelephonyConnectionServiceProxy.java b/src/com/android/services/telephony/TelephonyConnectionServiceProxy.java
index 604cf03..6c29bd2 100644
--- a/src/com/android/services/telephony/TelephonyConnectionServiceProxy.java
+++ b/src/com/android/services/telephony/TelephonyConnectionServiceProxy.java
@@ -30,16 +30,9 @@
     Collection<Connection> getAllConnections();
     void addConference(TelephonyConference mTelephonyConference);
     void addConference(ImsConference mImsConference);
-    void removeConnection(Connection connection);
     void addExistingConnection(PhoneAccountHandle phoneAccountHandle,
             Connection connection);
     void addExistingConnection(PhoneAccountHandle phoneAccountHandle,
                                Connection connection, Conference conference);
     void addConnectionToConferenceController(TelephonyConnection connection);
-
-    /**
-     * Called when a connection's conference membership changes.
-     * @param connection The connection.
-     */
-    void onConferenceMembershipChanged(Connection connection);
 }
diff --git a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java
index 139f8ac..5c0416b 100644
--- a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java
@@ -182,7 +182,7 @@
         try {
             mImsManager = ImsMmTelManager.createForSubscriptionId(
                     SubscriptionManager.getDefaultVoiceSubscriptionId());
-            mImsManager.registerImsRegistrationCallback(mRegistrationCallback, getMainExecutor());
+            mImsManager.registerImsRegistrationCallback(getMainExecutor(), mRegistrationCallback);
         } catch (IllegalArgumentException | ImsException e) {
             Log.w("ImsCallingActivity", "illegal subscription ID.");
         }
diff --git a/tests/Android.mk b/tests/Android.mk
index 44bf176..a8bd204 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_MODULE_TAGS := tests
 
-LOCAL_JAVA_LIBRARIES := telephony-common android.test.base
+LOCAL_JAVA_LIBRARIES := telephony-common android.test.base ims-common
 
 LOCAL_INSTRUMENTATION_FOR := TeleService
 
diff --git a/tests/src/com/android/phone/CnapTest.java b/tests/src/com/android/phone/CnapTest.java
deleted file mode 100644
index 534d02a..0000000
--- a/tests/src/com/android/phone/CnapTest.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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.
- */
-
-// Need to be in this package to access package methods.
-package com.android.phone;
-import android.content.Context;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.telephony.CallerInfo;
-
-import static com.android.internal.telephony.PhoneConstants.PRESENTATION_ALLOWED;
-import static com.android.internal.telephony.PhoneConstants.PRESENTATION_UNKNOWN;
-
-// Test suite for the Caller Name Presentation (CNAP) handling.
-// See AndroidManifest.xml how to run these tests.
-public class CnapTest extends AndroidTestCase {
-    private static final String TAG = "CnapTest";
-    private Context mContext;
-    private CallerInfo mCallerInfo;
-    // TODO: This string should be loaded from the phone package and
-    // not hardcoded.
-    private String mUnknown = "Unknown";
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getContext();
-        mCallerInfo = new CallerInfo();
-    }
-
-    // Checks the cnap 'ABSENT NUMBER' is mapped to the unknown presentation.
-    @SmallTest
-    public void testAbsentNumberIsMappedToUnknown() throws Exception {
-        String num = modifyForSpecialCnapCases("ABSENT NUMBER", PRESENTATION_ALLOWED);
-        assertIsUnknown(num);
-    }
-
-    // HELPERS
-
-    /**
-     * Checks the number and CallerInfo structure indicate the number
-     * is unknown.
-     */
-    private void assertIsUnknown(String number) {
-        assertEquals(mUnknown, number);
-        assertEquals(PRESENTATION_UNKNOWN, mCallerInfo.numberPresentation);
-        // TODO: cnapName and name presentation should be set to
-        // unknown. At least I cannot see why it shouldn't be the case
-        // assertEquals(mUnknown, mCallerInfo.cnapName);
-        // assertEquals(PRESENTATION_UNKNOWN, mCallerInfo.namePresentation);
-    }
-
-    /**
-     * Shorthand for PhoneUtils.modifyForSpecialCnapCases(mContext, mCallerInfo, ...)
-     */
-    private String modifyForSpecialCnapCases(String number, int presentation) {
-        return PhoneUtils.modifyForSpecialCnapCases(
-            mContext, mCallerInfo, number, presentation);
-    }
-}
diff --git a/tests/src/com/android/services/telephony/ConferenceParticipantConnectionTest.java b/tests/src/com/android/services/telephony/ConferenceParticipantConnectionTest.java
index 4336a20..ede0965 100644
--- a/tests/src/com/android/services/telephony/ConferenceParticipantConnectionTest.java
+++ b/tests/src/com/android/services/telephony/ConferenceParticipantConnectionTest.java
@@ -16,7 +16,7 @@
 
 package com.android.services.telephony;
 
-import static android.telecom.ConferenceParticipant.getParticipantAddress;
+import static com.android.ims.internal.ConferenceParticipant.getParticipantAddress;
 
 import static org.junit.Assert.assertEquals;
 
diff --git a/tests/src/com/android/services/telephony/ImsConferenceTest.java b/tests/src/com/android/services/telephony/ImsConferenceTest.java
index 6f8b3e8..7251402 100644
--- a/tests/src/com/android/services/telephony/ImsConferenceTest.java
+++ b/tests/src/com/android/services/telephony/ImsConferenceTest.java
@@ -31,11 +31,12 @@
 import android.os.Looper;
 import android.telecom.Call;
 import android.telecom.Conference;
-import android.telecom.ConferenceParticipant;
 import android.telecom.Connection;
 import android.telecom.PhoneAccountHandle;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import com.android.ims.internal.ConferenceParticipant;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
@@ -97,8 +98,6 @@
         imsConference.handleConferenceParticipantsUpdate(mConferenceHost,
                 Arrays.asList(participant1));
         assertEquals(0, imsConference.getNumberOfParticipants());
-        verify(mMockTelephonyConnectionServiceProxy, times(2)).removeConnection(
-                any(Connection.class));
         reset(mMockTelephonyConnectionServiceProxy);
 
         // Back to 2!
@@ -161,8 +160,6 @@
         imsConference.handleConferenceParticipantsUpdate(mConferenceHost,
                 Arrays.asList(participant1, participant2, participant3Disconnected));
         assertEquals(2, imsConference.getNumberOfParticipants());
-        verify(mMockTelephonyConnectionServiceProxy, times(1)).removeConnection(
-                any(Connection.class));
         reset(mMockTelephonyConnectionServiceProxy);
 
         // Now remove it from another CEP update; should still be the same number of participants
@@ -170,8 +167,6 @@
         imsConference.handleConferenceParticipantsUpdate(mConferenceHost,
                 Arrays.asList(participant1, participant2));
         assertEquals(2, imsConference.getNumberOfParticipants());
-        verify(mMockTelephonyConnectionServiceProxy, never()).removeConnection(
-                any(Connection.class));
         verify(mMockTelephonyConnectionServiceProxy, never()).addExistingConnection(
                 any(PhoneAccountHandle.class), any(Connection.class),
                 any(Conference.class));
@@ -222,8 +217,6 @@
         imsConference.handleConferenceParticipantsUpdate(mConferenceHost,
                 Arrays.asList(participant1, participant2));
         assertEquals(2, imsConference.getNumberOfParticipants());
-        verify(mMockTelephonyConnectionServiceProxy, times(1)).removeConnection(
-                any(Connection.class));
         verify(mMockTelephonyConnectionServiceProxy, never()).addExistingConnection(
                 any(PhoneAccountHandle.class), any(Connection.class),
                 any(Conference.class));
@@ -280,8 +273,6 @@
         imsConference.handleConferenceParticipantsUpdate(mConferenceHost,
                 Arrays.asList(participant1, participant2Disconnected));
         assertEquals(0, imsConference.getNumberOfParticipants());
-        verify(mMockTelephonyConnectionServiceProxy, times(2)).removeConnection(
-                any(Connection.class));
         reset(mMockTelephonyConnectionServiceProxy);
 
         // Pretend to merge someone else into the conference.
@@ -310,14 +301,14 @@
                 null /* phoneAccountHandle */, () -> true /* featureFlagProxy */);
 
         final boolean[] isConferenceState = new boolean[1];
-        Conference.Listener conferenceListener = new Conference.Listener() {
+        TelephonyConferenceBase.TelephonyConferenceListener conferenceListener =
+                new TelephonyConferenceBase.TelephonyConferenceListener() {
             @Override
-            public void onConferenceStateChanged(Conference c, boolean isConference) {
-                super.onConferenceStateChanged(c, isConference);
-                isConferenceState[0] = isConference;
+            public void onConferenceMembershipChanged(Connection connection) {
+                isConferenceState[0] = connection.getConference() != null;
             }
         };
-        imsConference.addListener(conferenceListener);
+        imsConference.addTelephonyConferenceListener(conferenceListener);
 
         ConferenceParticipant participant1 = new ConferenceParticipant(
                 Uri.parse("tel:6505551212"),
@@ -342,8 +333,6 @@
         imsConference.handleConferenceParticipantsUpdate(mConferenceHost,
                 Arrays.asList(participant1));
         assertEquals(0, imsConference.getNumberOfParticipants());
-        verify(mMockTelephonyConnectionServiceProxy, times(2)).removeConnection(
-                any(Connection.class));
 
         // Emulate a pre-disconnect conference event package; there will be zero participants.
         imsConference.handleConferenceParticipantsUpdate(mConferenceHost,
diff --git a/tests/src/com/android/services/telephony/TelephonyConferenceControllerTest.java b/tests/src/com/android/services/telephony/TelephonyConferenceControllerTest.java
index 4fc8c02..cfdc2fd 100644
--- a/tests/src/com/android/services/telephony/TelephonyConferenceControllerTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConferenceControllerTest.java
@@ -48,7 +48,7 @@
     private TelephonyConnectionServiceProxy mMockTelephonyConnectionServiceProxy;
 
     @Mock
-    private Conference.Listener mMockListener;
+    private TelephonyConferenceBase.TelephonyConferenceListener mMockListener;
 
     private TestTelephonyConnection mTestTelephonyConnectionA;
     private TestTelephonyConnection mTestTelephonyConnectionB;
@@ -158,7 +158,7 @@
         verify(mMockTelephonyConnectionServiceProxy).addConference(argumentCaptor.capture());
 
         // add a listener to the added conference
-        argumentCaptor.getValue().addListener(mMockListener);
+        argumentCaptor.getValue().addTelephonyConferenceListener(mMockListener);
 
         verify(mMockListener, never()).onDestroyed(any(Conference.class));