Merge "Add ability to disable conference event package handling from command line."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 49c1571..c4c33ca 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -199,6 +199,10 @@
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
     <uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE" />
     <uses-permission android:name="android.permission.MANAGE_ROLE_HOLDERS" />
+    <!-- Allows us to whitelist receivers of the
+         ACTION_SIM_SLOT_STATUS_CHANGED broadcast to start activities
+         from the background.  -->
+    <uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
 
     <application android:name="PhoneApp"
             android:persistent="true"
diff --git a/ecc/input/eccdata.txt b/ecc/input/eccdata.txt
index bf5d92c..403cad7 100644
--- a/ecc/input/eccdata.txt
+++ b/ecc/input/eccdata.txt
@@ -600,11 +600,8 @@
 countries {
   iso_code: "DE"
   eccs {
-    phone_number: "110"
-    types: POLICE
-  }
-  eccs {
     phone_number: "112"
+    types: POLICE
     types: AMBULANCE
     types: FIRE
   }
diff --git a/ecc/output/eccdata b/ecc/output/eccdata
index 2b9007a..917273d 100644
--- a/ecc/output/eccdata
+++ b/ecc/output/eccdata
Binary files differ
diff --git a/res/layout/emergency_dialer.xml b/res/layout/emergency_dialer.xml
index 6247379..892b8f4 100644
--- a/res/layout/emergency_dialer.xml
+++ b/res/layout/emergency_dialer.xml
@@ -108,7 +108,7 @@
                     <View
                         android:layout_width="match_parent"
                         android:layout_height="match_parent"
-                        android:backgroundTint="#ffe53935"
+                        android:backgroundTint="#ffe32926"
                         android:focusable="false"
                         android:clickable="false"
                         style="?android:attr/buttonStyle"/>
diff --git a/src/com/android/phone/CallBarringDeselectAllPreference.java b/src/com/android/phone/CallBarringDeselectAllPreference.java
index 153bc0c..e9310f8 100644
--- a/src/com/android/phone/CallBarringDeselectAllPreference.java
+++ b/src/com/android/phone/CallBarringDeselectAllPreference.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.os.Bundle;
-import android.telephony.ServiceState;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.View;
@@ -52,9 +51,7 @@
     protected void showDialog(Bundle state) {
         // Finds out if the password field should be shown or not.
         ImsPhone imsPhone = mPhone != null ? (ImsPhone) mPhone.getImsPhone() : null;
-        mShowPassword = !(imsPhone != null
-                && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
-                        || imsPhone.isUtEnabled()));
+        mShowPassword = !(imsPhone != null && imsPhone.isUtEnabled());
 
         // Selects dialog message depending on if the password field is shown or not.
         setDialogMessage(getContext().getString(mShowPassword
diff --git a/src/com/android/phone/CallBarringEditPreference.java b/src/com/android/phone/CallBarringEditPreference.java
index 72b3ea5..edff1e3 100644
--- a/src/com/android/phone/CallBarringEditPreference.java
+++ b/src/com/android/phone/CallBarringEditPreference.java
@@ -26,7 +26,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
-import android.telephony.ServiceState;
 import android.text.method.DigitsKeyListener;
 import android.text.method.PasswordTransformationMethod;
 import android.util.AttributeSet;
@@ -257,9 +256,7 @@
 
     private void setShowPassword() {
         ImsPhone imsPhone = mPhone != null ? (ImsPhone) mPhone.getImsPhone() : null;
-        mShowPassword = !(imsPhone != null
-                && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
-                        || imsPhone.isUtEnabled()));
+        mShowPassword = !(imsPhone != null && imsPhone.isUtEnabled());
     }
 
     @Override
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 48047ca..d1eb3dc 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -194,7 +194,7 @@
 
                 case EVENT_SYSTEM_UNLOCKED:
                 {
-                    for (int i = 0; i < TelephonyManager.from(mContext).getPhoneCount(); ++i) {
+                    for (int i = 0; i < TelephonyManager.from(mContext).getMaxPhoneCount(); ++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.
@@ -211,7 +211,7 @@
                     // Only update if there are cached config removed to avoid updating config for
                     // unrelated packages.
                     if (clearCachedConfigForPackage(carrierPackageName)) {
-                        int numPhones = TelephonyManager.from(mContext).getPhoneCount();
+                        int numPhones = TelephonyManager.from(mContext).getMaxPhoneCount();
                         for (int i = 0; i < numPhones; ++i) {
                             updateConfigForPhoneId(i);
                         }
@@ -523,7 +523,7 @@
         pkgFilter.addDataScheme("package");
         context.registerReceiver(mPackageReceiver, pkgFilter);
 
-        int numPhones = TelephonyManager.from(context).getPhoneCount();
+        int numPhones = TelephonyManager.from(context).getMaxPhoneCount();
         mConfigFromDefaultApp = new PersistableBundle[numPhones];
         mConfigFromCarrierApp = new PersistableBundle[numPhones];
         mOverrideConfigs = new PersistableBundle[numPhones];
diff --git a/src/com/android/phone/EmergencyCallbackModeExitDialog.java b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
index 2492f46..dcfa024 100644
--- a/src/com/android/phone/EmergencyCallbackModeExitDialog.java
+++ b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
@@ -68,6 +68,7 @@
     private boolean mInEmergencyCall = false;
     private static final int ECM_TIMER_RESET = 1;
     private Phone mPhone = null;
+    private boolean mIsResumed = false;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -100,6 +101,18 @@
     }
 
     @Override
+    public void onResume() {
+        super.onResume();
+        mIsResumed = true;
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        mIsResumed = false;
+    }
+
+    @Override
     public void onDestroy() {
         super.onDestroy();
         try {
@@ -176,7 +189,7 @@
      * Shows Emergency Callback Mode dialog and starts countdown timer
      */
     private void showEmergencyCallbackModeExitDialog() {
-        if (!this.isResumed()) {
+        if (!mIsResumed) {
             Log.w(TAG, "Tried to show dialog, but activity was already finished");
             return;
         }
diff --git a/src/com/android/phone/GsmUmtsCallBarringOptions.java b/src/com/android/phone/GsmUmtsCallBarringOptions.java
index a6f9844..3c9cd84 100644
--- a/src/com/android/phone/GsmUmtsCallBarringOptions.java
+++ b/src/com/android/phone/GsmUmtsCallBarringOptions.java
@@ -27,7 +27,6 @@
 import android.preference.Preference;
 import android.preference.PreferenceScreen;
 import android.telephony.CarrierConfigManager;
-import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.util.Log;
@@ -423,9 +422,7 @@
         boolean useDisableaAll = true;
 
         ImsPhone imsPhone = mPhone != null ? (ImsPhone) mPhone.getImsPhone() : null;
-        if (imsPhone != null
-                && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
-                        || imsPhone.isUtEnabled())) {
+        if (imsPhone != null && imsPhone.isUtEnabled()) {
             usePassword = false;
             useDisableaAll = false;
         }
diff --git a/src/com/android/phone/GsmUmtsCallForwardOptions.java b/src/com/android/phone/GsmUmtsCallForwardOptions.java
index b8ea8fd..10bd8d7 100644
--- a/src/com/android/phone/GsmUmtsCallForwardOptions.java
+++ b/src/com/android/phone/GsmUmtsCallForwardOptions.java
@@ -18,6 +18,7 @@
 import java.util.ArrayList;
 
 public class GsmUmtsCallForwardOptions extends TimeConsumingPreferenceActivity {
+    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
     private static final String LOG_TAG = "GsmUmtsCallForwardOptions";
 
     private static final String NUM_PROJECTION[] = {
@@ -62,6 +63,7 @@
         mPhone = mSubscriptionInfoHelper.getPhone();
 
         PersistableBundle b = null;
+        boolean supportCFNRc = true;
         if (mSubscriptionInfoHelper.hasSubId()) {
             b = PhoneGlobals.getInstance().getCarrierConfigForSubId(
                     mSubscriptionInfoHelper.getSubId());
@@ -73,6 +75,8 @@
                     CarrierConfigManager.KEY_CALL_FORWARDING_MAP_NON_NUMBER_TO_VOICEMAIL_BOOL);
             mCallForwardByUssd = b.getBoolean(
                     CarrierConfigManager.KEY_USE_CALL_FORWARDING_USSD_BOOL);
+            supportCFNRc = b.getBoolean(
+                    CarrierConfigManager.KEY_CALL_FORWARDING_WHEN_UNREACHABLE_SUPPORTED_BOOL);
         }
 
         PreferenceScreen prefSet = getPreferenceScreen();
@@ -89,7 +93,16 @@
         mPreferences.add(mButtonCFU);
         mPreferences.add(mButtonCFB);
         mPreferences.add(mButtonCFNRy);
-        mPreferences.add(mButtonCFNRc);
+
+        if (supportCFNRc) {
+            mPreferences.add(mButtonCFNRc);
+        } else {
+            // When CFNRc is not supported, mButtonCFNRc is grayed out from the menu.
+            // Default state for the preferences in this PreferenceScreen is disabled.
+            // Only preferences listed in the ArrayList mPreferences will be enabled.
+            // By not adding mButtonCFNRc to mPreferences it will be kept disabled.
+            if (DBG) Log.d(LOG_TAG, "onCreate: CFNRc is not supported, grey out the item.");
+        }
 
         if (mCallForwardByUssd) {
             //the call forwarding ussd command's behavior is similar to the call forwarding when
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index d0eda12..e5e9fe7 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -153,6 +153,7 @@
 import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
+import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
 import com.android.internal.telephony.uicc.IccIoResult;
 import com.android.internal.telephony.uicc.IccUtils;
 import com.android.internal.telephony.uicc.SIMRecords;
@@ -2040,7 +2041,7 @@
     private int getTargetSdk(String packageName) {
         try {
             final ApplicationInfo ai = mApp.getPackageManager().getApplicationInfoAsUser(
-                    packageName, 0, UserHandle.getUserId(Binder.getCallingUid()));
+                    packageName, 0, UserHandle.getUserHandleForUid(Binder.getCallingUid()));
             if (ai != null) return ai.targetSdkVersion;
         } catch (PackageManager.NameNotFoundException unexpected) {
             loge("Failed to get package info for pkg="
@@ -2720,7 +2721,7 @@
             if (phone != null) {
                 phone.setDataActivationState(activationState);
             } else {
-                loge("setVoiceActivationState fails with invalid subId: " + subId);
+                loge("setDataActivationState fails with invalid subId: " + subId);
             }
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -4811,13 +4812,13 @@
     public int getCarrierPrivilegeStatusForUid(int subId, int uid) {
         final Phone phone = getPhone(subId);
         if (phone == null) {
-            loge("getCarrierPrivilegeStatus: Invalid subId");
+            loge("getCarrierPrivilegeStatusForUid: Invalid subId");
             return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
         }
         UiccProfile profile =
                 UiccController.getInstance().getUiccProfileForPhone(phone.getPhoneId());
         if (profile == null) {
-            loge("getCarrierPrivilegeStatus: No UICC");
+            loge("getCarrierPrivilegeStatusForUid: No UICC");
             return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
         }
         return profile.getCarrierPrivilegeStatusForUid(phone.getContext().getPackageManager(), uid);
@@ -4868,7 +4869,7 @@
         }
         UiccCard card = UiccController.getInstance().getUiccCard(phoneId);
         if (card == null) {
-            loge("getCarrierPackageNamesForIntent: No UICC");
+            loge("getCarrierPackageNamesForIntentAndPhone: No UICC");
             return null ;
         }
         return card.getCarrierPackageNamesForIntent(mApp.getPackageManager(), intent);
@@ -5319,14 +5320,19 @@
     }
 
     /**
-     * Determines whether the user has turned on RTT. Only returns true if the device and carrier
-     * both also support RTT.
+     * Determines whether the user has turned on RTT. If the carrier wants to ignore the user-set
+     * RTT setting, will return true if the device and carrier both support RTT.
+     * Otherwise. only returns true if the device and carrier both also support RTT.
      */
     public boolean isRttEnabled(int subscriptionId) {
         final long identity = Binder.clearCallingIdentity();
         try {
-            return isRttSupported(subscriptionId) && Settings.Secure.getInt(
+            boolean isRttSupported = isRttSupported(subscriptionId);
+            boolean isUserRttSettingOn = Settings.Secure.getInt(
                     mApp.getContentResolver(), Settings.Secure.RTT_CALLING_MODE, 0) != 0;
+            boolean shouldIgnoreUserRttSetting = mApp.getCarrierConfigForSubId(subscriptionId)
+                    .getBoolean(CarrierConfigManager.KEY_IGNORE_RTT_MODE_SETTING_BOOL);
+            return isRttSupported && (isUserRttSettingOn || shouldIgnoreUserRttSetting);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -6453,7 +6459,10 @@
                 if (card != null) {
                     cardId = card.getCardId();
                 } else {
-                    cardId = slot.getIccId();
+                    cardId = slot.getEid();
+                    if (TextUtils.isEmpty(cardId)) {
+                        cardId = slot.getIccId();
+                    }
                 }
 
                 if (cardId != null) {
@@ -7007,6 +7016,33 @@
         }
     }
 
+    @Override
+    public boolean isApplicationOnUicc(int subId, int appType) {
+        enforceReadPrivilegedPermission("isApplicationOnUicc");
+        Phone phone = getPhone(subId);
+        if (phone == null) {
+            return false;
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            UiccCard uiccCard = phone.getUiccCard();
+            if (uiccCard == null) {
+                return false;
+            }
+            UiccProfile uiccProfile = uiccCard.getUiccProfile();
+            if (uiccProfile == null) {
+                return false;
+            }
+            if (TelephonyManager.APPTYPE_SIM <= appType
+                    && appType <= TelephonyManager.APPTYPE_ISIM) {
+                return uiccProfile.isApplicationOnIcc(AppType.values()[appType]);
+            }
+            return false;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     /**
      * Get whether making changes to modem configurations will trigger reboot.
      * Return value defaults to true.
diff --git a/src/com/android/phone/settings/AccessibilitySettingsFragment.java b/src/com/android/phone/settings/AccessibilitySettingsFragment.java
index 942f28c..5a70fe2 100644
--- a/src/com/android/phone/settings/AccessibilitySettingsFragment.java
+++ b/src/com/android/phone/settings/AccessibilitySettingsFragment.java
@@ -166,10 +166,17 @@
             int rttMode = mButtonRtt.isChecked() ? 1 : 0;
             Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.RTT_CALLING_MODE,
                     rttMode);
-            // Update RTT config with IMS Manager
-            ImsManager imsManager = ImsManager.getInstance(getContext(),
-                    SubscriptionManager.getDefaultVoicePhoneId());
-            imsManager.setRttEnabled(mButtonRtt.isChecked());
+            // Update RTT config with IMS Manager if the always-on carrier config isn't set to true.
+            CarrierConfigManager configManager = (CarrierConfigManager) mContext.getSystemService(
+                            Context.CARRIER_CONFIG_SERVICE);
+            for (int subId : SubscriptionController.getInstance().getActiveSubIdList(true)) {
+                if (!configManager.getConfigForSubId(subId).getBoolean(
+                        CarrierConfigManager.KEY_IGNORE_RTT_MODE_SETTING_BOOL, false)) {
+                    int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
+                    ImsManager imsManager = ImsManager.getInstance(getContext(), phoneId);
+                    imsManager.setRttEnabled(mButtonRtt.isChecked());
+                }
+            }
             return true;
         }
 
@@ -199,18 +206,23 @@
     }
 
     private boolean shouldShowRttSetting() {
-        int subscriptionId = SubscriptionManager.getDefaultVoiceSubscriptionId();
-        if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID
-                || subscriptionId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
-            for (int subId : SubscriptionController.getInstance().getActiveSubIdList(true)) {
-                if (PhoneGlobals.getInstance().phoneMgr.isRttSupported(subId)) {
+        CarrierConfigManager configManager =
+                (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        // Go through all the subs -- if we want to display the RTT setting for any of them, do
+        // display it.
+        for (int subId : SubscriptionController.getInstance().getActiveSubIdList(true)) {
+            // In order to display the setting, we want:
+            // 1. The subscription supports RTT
+            // 2. The subscription isn't configured by the carrier to have the setting always-on
+            //    (see the documentation for the carrier config key)
+            if (PhoneGlobals.getInstance().phoneMgr.isRttSupported(subId)) {
+                if (!configManager.getConfigForSubId(subId).getBoolean(
+                        CarrierConfigManager.KEY_IGNORE_RTT_MODE_SETTING_BOOL, false)) {
                     return true;
                 }
             }
-            return false;
-        } else {
-            return PhoneGlobals.getInstance().phoneMgr.isRttSupported(subscriptionId);
         }
+        return false;
     }
 
     /**
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index cf3f913..94e8c4a 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -18,10 +18,14 @@
 
 import android.content.Context;
 import android.media.ToneGenerator;
+import android.os.PersistableBundle;
 import android.telecom.DisconnectCause;
+import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 
 import com.android.internal.telephony.CallFailCause;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
 import com.android.phone.ImsUtil;
 import com.android.phone.PhoneGlobals;
 import com.android.phone.common.R;
@@ -102,7 +106,7 @@
                         telephonyPerciseDisconnectCause),
                 toTelecomDisconnectCauseDescription(context, telephonyDisconnectCause, phoneId),
                 toTelecomDisconnectReason(context,telephonyDisconnectCause, reason, phoneId),
-                toTelecomDisconnectCauseTone(telephonyDisconnectCause));
+                toTelecomDisconnectCauseTone(telephonyDisconnectCause, phoneId));
     }
 
     /**
@@ -793,11 +797,22 @@
     /**
      * Returns the tone to play for the disconnect cause, or UNKNOWN if none should be played.
      */
-    private static int toTelecomDisconnectCauseTone(int telephonyDisconnectCause) {
-        switch (telephonyDisconnectCause) {
-            case android.telephony.DisconnectCause.BUSY:
+    private static int toTelecomDisconnectCauseTone(int telephonyDisconnectCause, int phoneId) {
+        Phone phone = PhoneFactory.getPhone(phoneId);
+        PersistableBundle config;
+        if (phone != null) {
+            config = PhoneGlobals.getInstance().getCarrierConfigForSubId(phone.getSubId());
+        } else {
+            config = PhoneGlobals.getInstance().getCarrierConfig();
+        }
+        int[] busyToneArray = config.getIntArray(
+                CarrierConfigManager.KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY);
+        for (int busyTone : busyToneArray) {
+            if (busyTone == telephonyDisconnectCause) {
                 return ToneGenerator.TONE_SUP_BUSY;
-
+            }
+        }
+        switch (telephonyDisconnectCause) {
             case android.telephony.DisconnectCause.CONGESTION:
                 return ToneGenerator.TONE_SUP_CONGESTION;
 
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index 245f2e8..4da92e2 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -829,7 +829,7 @@
             // If the single party call emulation fature flag is enabled, we can potentially treat
             // the conference as a single party call when there is just one participant.
             if (mFeatureFlagProxy.isUsingSinglePartyCallEmulation()) {
-                if (oldParticipantCount > 1 && newParticipantCount == 1) {
+                if (oldParticipantCount != 1 && newParticipantCount == 1) {
                     // If number of participants goes to 1, emulate a single party call.
                     startEmulatingSinglePartyCall();
                 } else if (mIsEmulatingSinglePartyCall && !isSinglePartyConference) {
@@ -1312,4 +1312,12 @@
         return isMaximumConferenceSizeEnforced()
                 && getNumberOfParticipants() >= getMaximumConferenceSize();
     }
+
+    /**
+     * @return {@code True} if the ImsConference is emulating single party call.
+     */
+    @VisibleForTesting
+    public boolean isEmulatingSinglePartyCall() {
+        return mIsEmulatingSinglePartyCall;
+    }
 }
diff --git a/src/com/android/services/telephony/RadioOnHelper.java b/src/com/android/services/telephony/RadioOnHelper.java
index 288c72c..85f94ab 100644
--- a/src/com/android/services/telephony/RadioOnHelper.java
+++ b/src/com/android/services/telephony/RadioOnHelper.java
@@ -53,7 +53,7 @@
             return;
         }
         mListeners = new ArrayList<>(2);
-        for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
+        for (int i = 0; i < TelephonyManager.getDefault().getMaxPhoneCount(); i++) {
             mListeners.add(new RadioOnStateListener());
         }
     }
@@ -76,7 +76,7 @@
         mCallback = callback;
         mInProgressListeners.clear();
         mIsRadioOnCallingEnabled = false;
-        for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
+        for (int i = 0; i < TelephonyManager.getDefault().getMaxPhoneCount(); i++) {
             Phone phone = PhoneFactory.getPhone(i);
             if (phone == null) {
                 continue;
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 7e29e85..84fa40c 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -1159,7 +1159,8 @@
                && isShowingOriginalDialString()) {
             Log.i(this, "new original dial string is null, convert to: "
                    +  mOriginalConnection.getOrigDialString());
-            originalConnection.setConverted(mOriginalConnection.getOrigDialString());
+            originalConnection.restoreDialedNumberAfterConversion(
+                    mOriginalConnection.getOrigDialString());
         }
 
         clearOriginalConnection();
@@ -2219,6 +2220,8 @@
         if (isIms) {
             isVoWifiEnabled = ImsUtil.isWfcEnabled(phone.getContext(), phone.getPhoneId());
         }
+        boolean isRttMergeSupported = getCarrierConfig()
+                .getBoolean(CarrierConfigManager.KEY_ALLOW_MERGING_RTT_CALLS_BOOL);
         PhoneAccountHandle phoneAccountHandle = isIms ? PhoneUtils
                 .makePstnPhoneAccountHandle(phone.getDefaultPhone())
                 : PhoneUtils.makePstnPhoneAccountHandle(phone);
@@ -2243,7 +2246,7 @@
         if (mTreatAsEmergencyCall) {
             isConferenceSupported = false;
             Log.d(this, "refreshConferenceSupported = false; emergency call");
-        } else if (isRtt()) {
+        } else if (isRtt() && !isRttMergeSupported) {
             isConferenceSupported = false;
             Log.d(this, "refreshConferenceSupported = false; rtt call");
         } else if (!isConferencingSupported || isIms && !isImsConferencingSupported) {
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 927b2c9..0e5a612 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -25,6 +25,9 @@
 import android.content.IntentFilter;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
 import android.provider.Settings;
 import android.telecom.Conference;
 import android.telecom.Connection;
@@ -176,6 +179,8 @@
     // destroyed.
     @VisibleForTesting
     public Pair<WeakReference<TelephonyConnection>, Queue<Phone>> mEmergencyRetryCache;
+    private Handler mDdsSwitchHandler;
+    private HandlerThread mHandlerThread;
 
     /**
      * Keeps track of the status of a SIM slot.
@@ -329,11 +334,17 @@
         IntentFilter intentFilter = new IntentFilter(
                 TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED);
         registerReceiver(mTtyBroadcastReceiver, intentFilter);
+
+        mHandlerThread = new HandlerThread("DdsSwitchHandlerThread");
+        mHandlerThread.start();
+        Looper looper = mHandlerThread.getLooper();
+        mDdsSwitchHandler = new Handler(looper);
     }
 
     @Override
     public boolean onUnbind(Intent intent) {
         unregisterReceiver(mTtyBroadcastReceiver);
+        mHandlerThread.quitSafely();
         return super.onUnbind(intent);
     }
 
@@ -523,14 +534,14 @@
             } else {
                 final Connection resultConnection = getTelephonyConnection(request, numberToDial,
                         true, handle, phone);
-                CompletableFuture<Boolean> phoneFuture = delayDialForDdsSwitch(phone);
-                phoneFuture.whenComplete((result, error) -> {
-                    if (error != null) {
-                        Log.w(this, "onCreateOutgoingConn - delayDialForDdsSwitch exception= "
-                                + error.getMessage());
+                mDdsSwitchHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        boolean result = delayDialForDdsSwitch(phone);
+                        Log.i(this,
+                                "onCreateOutgoingConn - delayDialForDdsSwitch result = " + result);
+                        placeOutgoingConnection(request, resultConnection, phone);
                     }
-                    Log.i(this, "onCreateOutgoingConn - delayDialForDdsSwitch result = " + result);
-                    placeOutgoingConnection(request, resultConnection, phone);
                 });
                 return resultConnection;
             }
@@ -604,14 +615,14 @@
                 adjustAndPlaceOutgoingConnection(phone, originalConnection, request, numberToDial,
                         handle, originalPhoneType, false);
             } else {
-                delayDialForDdsSwitch(phone).whenComplete((result, error) -> {
-                    if (error != null) {
-                        Log.w(this, "handleOnComplete - delayDialForDdsSwitch exception= "
-                                + error.getMessage());
+                mDdsSwitchHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        boolean result = delayDialForDdsSwitch(phone);
+                        Log.i(this, "handleOnComplete - delayDialForDdsSwitch result = " + result);
+                        adjustAndPlaceOutgoingConnection(phone, originalConnection, request,
+                                numberToDial, handle, originalPhoneType, true);
                     }
-                    Log.i(this, "handleOnComplete - delayDialForDdsSwitch result = " + result);
-                    adjustAndPlaceOutgoingConnection(phone, originalConnection, request,
-                            numberToDial, handle, originalPhoneType, true);
                 });
             }
 
@@ -1234,6 +1245,11 @@
         com.android.internal.telephony.Connection originalConnection = null;
         try {
             if (phone != null) {
+                EmergencyNumber emergencyNumber =
+                        phone.getEmergencyNumberTracker().getEmergencyNumber(number);
+                if (emergencyNumber != null) {
+                    phone.notifyOutgoingEmergencyCall(emergencyNumber);
+                }
                 originalConnection = phone.dial(number, new ImsPhone.ImsDialArgs.Builder()
                         .setVideoState(videoState)
                         .setIntentExtras(extras)
@@ -1375,13 +1391,22 @@
         return chosenPhone;
     }
 
-    private CompletableFuture<Boolean> delayDialForDdsSwitch(Phone phone) {
+    /**
+     * If needed, block until the the default data is is switched for outgoing emergency call, or
+     * timeout expires.
+     */
+    private boolean delayDialForDdsSwitch(Phone phone) {
         if (phone == null) {
-            return CompletableFuture.completedFuture(Boolean.TRUE);
+            return true;
         }
-        return possiblyOverrideDefaultDataForEmergencyCall(phone)
-                .completeOnTimeout(false, DEFAULT_DATA_SWITCH_TIMEOUT_MS,
-                        TimeUnit.MILLISECONDS);
+        try {
+            return possiblyOverrideDefaultDataForEmergencyCall(phone).get(
+                    DEFAULT_DATA_SWITCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (Exception e) {
+            Log.w(this, "onCreateOutgoingConn - delayDialForDdsSwitch exception= "
+                    + e.getMessage());
+            return false;
+        }
     }
 
     /**
diff --git a/tests/src/com/android/services/telephony/ImsConferenceTest.java b/tests/src/com/android/services/telephony/ImsConferenceTest.java
index 68b5b3b..568549b 100644
--- a/tests/src/com/android/services/telephony/ImsConferenceTest.java
+++ b/tests/src/com/android/services/telephony/ImsConferenceTest.java
@@ -16,19 +16,16 @@
 
 package com.android.services.telephony;
 
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.times;
-
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.net.Uri;
 import android.os.Looper;
@@ -39,15 +36,10 @@
 import android.telecom.PhoneAccountHandle;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import com.android.internal.telephony.PhoneConstants;
-
 import org.junit.Before;
 import org.junit.Test;
-
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
 import java.util.Arrays;
 
@@ -179,6 +171,31 @@
     }
 
     /**
+     * Verify that the single party emulate correctly when the conference start with only
+     * one participant.
+     */
+    @Test
+    @SmallTest
+    public void testSinglePartyEmulationWithOneParticipantAtBeginning() {
+        when(mMockTelecomAccountRegistry.isUsingSimCallManager(any(PhoneAccountHandle.class)))
+                .thenReturn(false);
+
+        ImsConference imsConference = new ImsConference(mMockTelecomAccountRegistry,
+                mMockTelephonyConnectionServiceProxy, mConferenceHost,
+                null /* phoneAccountHandle */, () -> true /* featureFlagProxy */);
+
+        ConferenceParticipant participant1 = new ConferenceParticipant(
+                Uri.parse("tel:6505551212"),
+                "A",
+                Uri.parse("sip:6505551212@testims.com"),
+                Connection.STATE_ACTIVE,
+                Call.Details.DIRECTION_INCOMING);
+        imsConference.handleConferenceParticipantsUpdate(mConferenceHost,
+                Arrays.asList(participant1));
+        assertTrue(imsConference.isEmulatingSinglePartyCall());
+    }
+
+    /**
      * Verify that we do not use single party emulation when a sim call manager is in use.
      */
     @Test