Merge "Implement long sleep for VVM task scheduler" into nyc-mr1-dev
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 7d48272..997022d 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -210,7 +210,7 @@
     <string name="enhanced_4g_lte_mode_title" msgid="522191650223239171">"Tryb rozszerzonego 4G LTE"</string>
     <string name="enhanced_4g_lte_mode_title_variant" msgid="4871126028907265406">"Zaawansowane połączenia"</string>
     <string name="enhanced_4g_lte_mode_summary" msgid="2332175070522125850">"Użyj usług LTE, by poprawić łączność głosową i inną (zalecane)"</string>
-    <string name="data_enabled" msgid="5972538663568715366">"Włącz przesył danych"</string>
+    <string name="data_enabled" msgid="5972538663568715366">"Włączone przesyłanie danych"</string>
     <string name="data_enable_summary" msgid="2382798156640007971">"Zezwalaj na transmisję danych"</string>
     <string name="dialog_alert_title" msgid="6751344986194435476">"Uwaga"</string>
     <string name="roaming" msgid="8871412572928323707">"Roaming danych"</string>
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index 227e112..1d34788 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -515,6 +515,11 @@
      */
     private void placeCall() {
         mLastNumber = mDigits.getText().toString();
+        // Convert into emergency number if necessary
+        // This is required in some regions (e.g. Taiwan).
+        if (PhoneNumberUtils.isConvertToEmergencyNumberEnabled()) {
+            mLastNumber = PhoneNumberUtils.convertToEmergencyNumber(mLastNumber);
+        }
         if (PhoneNumberUtils.isLocalEmergencyNumber(this, mLastNumber)) {
             if (DBG) Log.d(LOG_TAG, "placing call to " + mLastNumber);
 
diff --git a/src/com/android/phone/vvm/omtp/ActivationTask.java b/src/com/android/phone/vvm/omtp/ActivationTask.java
index 00dd49e..e1fea4d 100644
--- a/src/com/android/phone/vvm/omtp/ActivationTask.java
+++ b/src/com/android/phone/vvm/omtp/ActivationTask.java
@@ -43,6 +43,7 @@
 import java.io.IOException;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.concurrent.CancellationException;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
 
@@ -62,14 +63,12 @@
 
     private static final String EXTRA_MESSAGE_DATA_BUNDLE = "extra_message_data_bundle";
 
-    public static final String EXTRA_REGISTER_CONTENT_PROVIDER = "extra_register_content_provider";
-
     @Nullable
     private static DeviceProvisionedObserver sDeviceProvisionedObserver;
 
     private final RetryPolicy mRetryPolicy;
 
-    private Bundle mData;
+    private Bundle mMessageData;
 
     public ActivationTask() {
         super(TASK_ACTIVATION);
@@ -85,7 +84,12 @@
             context.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) == 1;
     }
 
-    public static void start(Context context, int subId, @Nullable Bundle data) {
+    /**
+     * @param messageData The optional bundle from {@link android.provider.VoicemailContract#
+     * EXTRA_VOICEMAIL_SMS_FIELDS}, if the task is initiated by a status SMS. If null the task will
+     * request a status SMS itself.
+     */
+    public static void start(Context context, int subId, @Nullable Bundle messageData) {
         if (!isDeviceProvisioned(context)) {
             VvmLog.i(TAG, "Activation requested while device is not provisioned, postponing");
             // Activation might need information such as system language to be set, so wait until
@@ -98,28 +102,26 @@
         // Check for signal before activating. The event often happen while boot and the
         // network is not connected yet. Launching activation will likely to cause the SMS
         // sending to fail and waste unnecessary time waiting for time out.
-        if (context.getSystemService(TelephonyManager.class)
-            .getServiceStateForSubscriber(subId).getState()
-            != ServiceState.STATE_IN_SERVICE) {
+        if (!hasSignal(context, subId)) {
             VvmLog.i(TAG, "Activation requested while not in service, rejecting");
         }
 
         Intent intent = BaseTask.createIntent(context, ActivationTask.class, subId);
-        if (data != null) {
-            intent.putExtra(EXTRA_MESSAGE_DATA_BUNDLE, data);
+        if (messageData != null) {
+            intent.putExtra(EXTRA_MESSAGE_DATA_BUNDLE, messageData);
         }
         context.startService(intent);
     }
 
     public void onCreate(Context context, Intent intent, int flags, int startId) {
         super.onCreate(context, intent, flags, startId);
-        mData = intent.getParcelableExtra(EXTRA_MESSAGE_DATA_BUNDLE);
+        mMessageData = intent.getParcelableExtra(EXTRA_MESSAGE_DATA_BUNDLE);
     }
 
     @Override
     public Intent createRestartIntent() {
         Intent intent = super.createRestartIntent();
-        // mData is discarded, request a fresh STATUS SMS for retries.
+        // mMessageData is discarded, request a fresh STATUS SMS for retries.
         return intent;
     }
 
@@ -136,6 +138,12 @@
             return;
         }
 
+        if (!hasSignal(getContext(), subId)) {
+            VvmLog.i(TAG, "Service lost during activation, aborting");
+            // Don't retry, a new activation will be started after the signal returned.
+            return;
+        }
+
         OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(getContext(), subId);
         if (!helper.isValid()) {
             VvmLog.i(TAG, "VVM not supported on subId " + subId);
@@ -143,19 +151,17 @@
             return;
         }
 
-        if (mData != null && mData.getBoolean(EXTRA_REGISTER_CONTENT_PROVIDER)) {
-            // OmtmVvmCarrierConfigHelper can start the activation process; it will pass in a vvm
-            // content provider URI which we will use.  On some occasions, setting that URI will
-            // fail, so we will perform a few attempts to ensure that the vvm content provider has
-            // a good chance of being started up.
-            if (!VoicemailStatus.edit(getContext(), phoneAccountHandle)
-                    .setType(helper.getVvmType())
-                    .apply()) {
-                VvmLog.e(TAG, "Failed to configure content provider - " + helper.getVvmType());
-                fail();
-            }
-            VvmLog.i(TAG, "VVM content provider configured - " + helper.getVvmType());
+        // OmtpVvmCarrierConfigHelper can start the activation process; it will pass in a vvm
+        // content provider URI which we will use.  On some occasions, setting that URI will
+        // fail, so we will perform a few attempts to ensure that the vvm content provider has
+        // a good chance of being started up.
+        if (!VoicemailStatus.edit(getContext(), phoneAccountHandle)
+            .setType(helper.getVvmType())
+            .apply()) {
+            VvmLog.e(TAG, "Failed to configure content provider - " + helper.getVvmType());
+            fail();
         }
+        VvmLog.i(TAG, "VVM content provider configured - " + helper.getVvmType());
 
         if (!OmtpVvmSourceManager.getInstance(getContext())
                 .isVvmSourceRegistered(phoneAccountHandle)) {
@@ -183,13 +189,13 @@
         VisualVoicemailProtocol protocol = helper.getProtocol();
 
         Bundle data;
-        if (mData != null) {
+        if (mMessageData != null) {
             // The content of STATUS SMS is provided to launch this task, no need to request it
             // again.
-            data = mData;
+            data = mMessageData;
         } else {
             try (StatusSmsFetcher fetcher = new StatusSmsFetcher(getContext(), subId)) {
-                protocol.startActivation(helper);
+                protocol.startActivation(helper, fetcher.getSentIntent());
                 // Both the fetcher and OmtpMessageReceiver will be triggered, but
                 // OmtpMessageReceiver will just route the SMS back to ActivationTask, which will be
                 // rejected because the task is still running.
@@ -200,6 +206,10 @@
                 helper.handleEvent(status, OmtpEvents.CONFIG_STATUS_SMS_TIME_OUT);
                 fail();
                 return;
+            } catch (CancellationException e) {
+                VvmLog.e(TAG, "Unable to send status request SMS");
+                fail();
+                return;
             } catch (InterruptedException | ExecutionException | IOException e) {
                 VvmLog.e(TAG, "can't get future STATUS SMS", e);
                 fail();
@@ -256,6 +266,11 @@
         }
     }
 
+    private static boolean hasSignal(Context context, int subId) {
+        return context.getSystemService(TelephonyManager.class)
+                .getServiceStateForSubscriber(subId).getState() == ServiceState.STATE_IN_SERVICE;
+    }
+
     private static void queueActivationAfterProvisioned(Context context, int subId) {
         if (sDeviceProvisionedObserver == null) {
             sDeviceProvisionedObserver = new DeviceProvisionedObserver(context);
diff --git a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
index 4d6c63c..0b321b5 100644
--- a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
+++ b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
@@ -16,6 +16,7 @@
 package com.android.phone.vvm.omtp;
 
 import android.annotation.Nullable;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Bundle;
@@ -328,9 +329,7 @@
         activateSmsFilter();
 
         if (mProtocol != null) {
-            Bundle extras = new Bundle();
-            extras.putBoolean(ActivationTask.EXTRA_REGISTER_CONTENT_PROVIDER, true);
-            ActivationTask.start(mContext, mSubId, extras);
+            ActivationTask.start(mContext, mSubId, null);
         }
     }
 
@@ -366,9 +365,9 @@
         }
     }
 
-    public void requestStatus() {
+    public void requestStatus(@Nullable PendingIntent sentIntent) {
         if (mProtocol != null) {
-            mProtocol.requestStatus(this);
+            mProtocol.requestStatus(this, sentIntent);
         }
     }
 
diff --git a/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocol.java b/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocol.java
index e0b6359..6e6d6ef 100644
--- a/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocol.java
+++ b/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocol.java
@@ -17,6 +17,7 @@
 package com.android.phone.vvm.omtp.protocol;
 
 import android.annotation.Nullable;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.os.Bundle;
 import android.telecom.PhoneAccountHandle;
@@ -34,10 +35,10 @@
     /**
      * Activation should cause the carrier to respond with a STATUS SMS.
      */
-    public void startActivation(OmtpVvmCarrierConfigHelper config) {
+    public void startActivation(OmtpVvmCarrierConfigHelper config, PendingIntent sentIntent) {
         OmtpMessageSender messageSender = ProtocolHelper.getMessageSender(this, config);
         if (messageSender != null) {
-            messageSender.requestVvmActivation(null);
+            messageSender.requestVvmActivation(sentIntent);
         }
     }
 
@@ -58,10 +59,11 @@
         // Do nothing
     }
 
-    public void requestStatus(OmtpVvmCarrierConfigHelper config) {
+    public void requestStatus(OmtpVvmCarrierConfigHelper config,
+            @Nullable PendingIntent sentIntent) {
         OmtpMessageSender messageSender = ProtocolHelper.getMessageSender(this, config);
         if (messageSender != null) {
-            messageSender.requestVvmStatus(null);
+            messageSender.requestVvmStatus(sentIntent);
         }
     }
 
diff --git a/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java b/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
index 39d2b34..72044e2 100644
--- a/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
+++ b/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
@@ -17,6 +17,7 @@
 package com.android.phone.vvm.omtp.protocol;
 
 import android.annotation.Nullable;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.net.Network;
 import android.os.Bundle;
@@ -82,12 +83,13 @@
     private static final int DEFAULT_PIN_LENGTH = 6;
 
     @Override
-    public void startActivation(OmtpVvmCarrierConfigHelper config) {
+    public void startActivation(OmtpVvmCarrierConfigHelper config,
+            @Nullable PendingIntent sentIntent) {
         // VVM3 does not support activation SMS.
         // Send a status request which will start the provisioning process if the user is not
         // provisioned.
         VvmLog.i(TAG, "Activating");
-        config.requestStatus();
+        config.requestStatus(sentIntent);
     }
 
     @Override
@@ -215,7 +217,7 @@
                     helper.closeNewUserTutorial();
                     VvmLog.i(TAG, "new user: NUT closed");
 
-                    config.requestStatus();
+                    config.requestStatus(null);
                 }
             } catch (InitializingException | MessagingException | IOException e) {
                 config.handleEvent(status, OmtpEvents.VVM3_NEW_USER_SETUP_FAILED);
diff --git a/src/com/android/phone/vvm/omtp/sms/StatusSmsFetcher.java b/src/com/android/phone/vvm/omtp/sms/StatusSmsFetcher.java
index 2c37dd9..2f3cbfa 100644
--- a/src/com/android/phone/vvm/omtp/sms/StatusSmsFetcher.java
+++ b/src/com/android/phone/vvm/omtp/sms/StatusSmsFetcher.java
@@ -17,13 +17,17 @@
 package com.android.phone.vvm.omtp.sms;
 
 import android.annotation.MainThread;
+import android.annotation.Nullable;
 import android.annotation.WorkerThread;
+import android.app.Activity;
+import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Bundle;
 import android.provider.VoicemailContract;
+import android.telephony.SmsManager;
 import com.android.phone.Assert;
 import com.android.phone.vvm.omtp.OmtpConstants;
 import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
@@ -31,6 +35,7 @@
 import com.android.phone.vvm.omtp.protocol.VisualVoicemailProtocol;
 import java.io.Closeable;
 import java.io.IOException;
+import java.util.concurrent.CancellationException;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
@@ -44,6 +49,8 @@
     private static final String TAG = "VvmStatusSmsFetcher";
 
     private static final long STATUS_SMS_TIMEOUT_MILLIS = 60_000;
+    private static final String ACTION_REQUEST_SENT_INTENT = "action_request_sent_intent";
+    private static final int ACTION_REQUEST_SENT_REQUEST_CODE = 0;
 
     private CompletableFuture<Bundle> mFuture = new CompletableFuture<>();
 
@@ -54,6 +61,7 @@
         mContext = context;
         mSubId = subId;
         IntentFilter filter = new IntentFilter(VoicemailContract.ACTION_VOICEMAIL_SMS_RECEIVED);
+        filter.addAction(ACTION_REQUEST_SENT_INTENT);
         context.registerReceiver(this, filter);
     }
 
@@ -63,16 +71,38 @@
     }
 
     @WorkerThread
-    public Bundle get()
-            throws InterruptedException, ExecutionException, TimeoutException {
+    @Nullable
+    public Bundle get() throws InterruptedException, ExecutionException, TimeoutException,
+            CancellationException {
         Assert.isNotMainThread();
         return mFuture.get(STATUS_SMS_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
     }
 
+    public PendingIntent getSentIntent() {
+        Intent intent = new Intent(ACTION_REQUEST_SENT_INTENT);
+        // Because the receiver is registered dynamically, implicit intent must be used.
+        // There should only be a single status SMS request at a time.
+        return PendingIntent.getBroadcast(mContext, ACTION_REQUEST_SENT_REQUEST_CODE, intent,
+                PendingIntent.FLAG_CANCEL_CURRENT);
+    }
+
     @Override
     @MainThread
     public void onReceive(Context context, Intent intent) {
         Assert.isMainThread();
+        if (ACTION_REQUEST_SENT_INTENT.equals(intent.getAction())) {
+            int resultCode = getResultCode();
+
+            if (resultCode == Activity.RESULT_OK) {
+                VvmLog.d(TAG, "Request SMS successfully sent");
+                return;
+            }
+
+            VvmLog.e(TAG, "Request SMS send failed: " + sentSmsResultToString(resultCode));
+            mFuture.cancel(true);
+            return;
+        }
+
         int subId = intent.getExtras().getInt(VoicemailContract.EXTRA_VOICEMAIL_SMS_SUBID);
 
         if (mSubId != subId) {
@@ -105,4 +135,21 @@
             mFuture.complete(translatedBundle);
         }
     }
+
+    private static String sentSmsResultToString(int resultCode) {
+        switch (resultCode) {
+            case Activity.RESULT_OK:
+                return "OK";
+            case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
+                return "RESULT_ERROR_GENERIC_FAILURE";
+            case SmsManager.RESULT_ERROR_NO_SERVICE:
+                return "RESULT_ERROR_GENERIC_FAILURE";
+            case SmsManager.RESULT_ERROR_NULL_PDU:
+                return "RESULT_ERROR_GENERIC_FAILURE";
+            case SmsManager.RESULT_ERROR_RADIO_OFF:
+                return "RESULT_ERROR_GENERIC_FAILURE";
+            default:
+                return "UNKNOWN CODE: " + resultCode;
+        }
+    }
 }
diff --git a/src/com/android/services/telephony/CdmaConferenceController.java b/src/com/android/services/telephony/CdmaConferenceController.java
index 9aee300..0a7c18b 100644
--- a/src/com/android/services/telephony/CdmaConferenceController.java
+++ b/src/com/android/services/telephony/CdmaConferenceController.java
@@ -90,6 +90,12 @@
     private CdmaConference mConference;
 
     void add(final CdmaConnection connection) {
+        if (mCdmaConnections.contains(connection)) {
+            // Adding a duplicate realistically shouldn't happen.
+            Log.w(this, "add - connection already tracked; connection=%s", connection);
+            return;
+        }
+
         if (!mCdmaConnections.isEmpty() && connection.isOutgoing()) {
             // There already exists a connection, so this will probably result in a conference once
             // it is added. For outgoing connections which are added while another connection
@@ -127,7 +133,14 @@
         recalculateConference();
     }
 
-    private void remove(CdmaConnection connection) {
+    void remove(CdmaConnection connection) {
+        if (!mCdmaConnections.contains(connection)) {
+            // Debug only since TelephonyConnectionService tries to clean up the connections tracked
+            // when the original connection changes.  It does this proactively.
+            Log.d(this, "remove - connection not tracked; connection=%s", connection);
+            return;
+        }
+
         connection.removeConnectionListener(mConnectionListener);
         mCdmaConnections.remove(connection);
         recalculateConference();
diff --git a/src/com/android/services/telephony/ImsConferenceController.java b/src/com/android/services/telephony/ImsConferenceController.java
index d017a9e..6669482 100644
--- a/src/com/android/services/telephony/ImsConferenceController.java
+++ b/src/com/android/services/telephony/ImsConferenceController.java
@@ -126,6 +126,12 @@
             return;
         }
 
+        if (mTelephonyConnections.contains(connection)) {
+            // Adding a duplicate realistically shouldn't happen.
+            Log.w(this, "add - connection already tracked; connection=%s", connection);
+            return;
+        }
+
         // Note: Wrap in Log.VERBOSE to avoid calling connection.toString if we are not going to be
         // outputting the value.
         if (Log.VERBOSE) {
@@ -149,10 +155,18 @@
             return;
         }
 
+        if (!mTelephonyConnections.contains(connection)) {
+            // Debug only since TelephonyConnectionService tries to clean up the connections tracked
+            // when the original connection changes.  It does this proactively.
+            Log.d(this, "remove - connection not tracked; connection=%s", connection);
+            return;
+        }
+
         if (Log.VERBOSE) {
             Log.v(this, "remove connection: %s", connection);
         }
 
+        connection.removeConnectionListener(mConnectionListener);
         mTelephonyConnections.remove(connection);
         recalculateConferenceable();
     }
diff --git a/src/com/android/services/telephony/TelephonyConferenceController.java b/src/com/android/services/telephony/TelephonyConferenceController.java
index fbf5ad0..5d59e17 100644
--- a/src/com/android/services/telephony/TelephonyConferenceController.java
+++ b/src/com/android/services/telephony/TelephonyConferenceController.java
@@ -84,12 +84,24 @@
     }
 
     void add(TelephonyConnection connection) {
+        if (mTelephonyConnections.contains(connection)) {
+            // Adding a duplicate realistically shouldn't happen.
+            Log.w(this, "add - connection already tracked; connection=%s", connection);
+            return;
+        }
+
         mTelephonyConnections.add(connection);
         connection.addConnectionListener(mConnectionListener);
         recalculate();
     }
 
     void remove(Connection connection) {
+        if (!mTelephonyConnections.contains(connection)) {
+            // Debug only since TelephonyConnectionService tries to clean up the connections tracked
+            // when the original connection changes.  It does this proactively.
+            Log.d(this, "remove - connection not tracked; connection=%s", connection);
+            return;
+        }
         connection.removeConnectionListener(mConnectionListener);
         mTelephonyConnections.remove(connection);
         recalculate();
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index a8f6bca..c26090e 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -112,7 +112,7 @@
         }
 
         String scheme = handle.getScheme();
-        final String number;
+        String number;
         if (PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
             // TODO: We don't check for SecurityException here (requires
             // CALL_PRIVILEGED permission).
@@ -176,14 +176,36 @@
             }
         }
 
-        final boolean isEmergencyNumber = PhoneNumberUtils.isLocalEmergencyNumber(this, number);
+        // Convert into emergency number if necessary
+        // This is required in some regions (e.g. Taiwan).
+        if (!PhoneNumberUtils.isLocalEmergencyNumber(this, number) &&
+                PhoneNumberUtils.isConvertToEmergencyNumberEnabled()) {
+            final Phone phone = getPhoneForAccount(request.getAccountHandle(), false);
+            // We only do the conversion if the phone is not in service. The un-converted
+            // emergency numbers will go to the correct destination when the phone is in-service,
+            // so they will only need the special emergency call setup when the phone is out of
+            // service.
+            if (phone == null || phone.getServiceState().getState()
+                    != ServiceState.STATE_IN_SERVICE) {
+                String convertedNumber = PhoneNumberUtils.convertToEmergencyNumber(number);
+                if (!TextUtils.equals(convertedNumber, number)) {
+                    Log.i(this, "onCreateOutgoingConnection, converted to emergency number");
+                    number = convertedNumber;
+                    handle = Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null);
+                }
+            }
+        }
+        final String numberToDial = number;
+
+        final boolean isEmergencyNumber =
+                PhoneNumberUtils.isLocalEmergencyNumber(this, numberToDial);
 
         if (isEmergencyNumber && !isRadioOn()) {
             final Uri emergencyHandle = handle;
             // By default, Connection based on the default Phone, since we need to return to Telecom
             // now.
             final int defaultPhoneType = PhoneFactory.getDefaultPhone().getPhoneType();
-            final Connection emergencyConnection = getTelephonyConnection(request, number,
+            final Connection emergencyConnection = getTelephonyConnection(request, numberToDial,
                     isEmergencyNumber, emergencyHandle, PhoneFactory.getDefaultPhone());
             if (mEmergencyCallHelper == null) {
                 mEmergencyCallHelper = new EmergencyCallHelper(this);
@@ -206,7 +228,7 @@
                         // Phone, then we need create a new Connection using that PhoneType and
                         // replace it in Telecom.
                         if (phone.getPhoneType() != defaultPhoneType) {
-                            Connection repConnection = getTelephonyConnection(request, number,
+                            Connection repConnection = getTelephonyConnection(request, numberToDial,
                                     isEmergencyNumber, emergencyHandle, phone);
                             // If there was a failure, the resulting connection will not be a
                             // TelephonyConnection, so don't place the call, just return!
@@ -256,8 +278,8 @@
 
             // Get the right phone object from the account data passed in.
             final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber);
-            Connection resultConnection = getTelephonyConnection(request, number, isEmergencyNumber,
-                    handle, phone);
+            Connection resultConnection = getTelephonyConnection(request, numberToDial,
+                    isEmergencyNumber, handle, phone);
             // If there was a failure, the resulting connection will not be a TelephonyConnection,
             // so don't place the call!
             if(resultConnection instanceof TelephonyConnection) {
@@ -785,22 +807,32 @@
      * @param connection The connection to be added to the controller
      */
     public void addConnectionToConferenceController(TelephonyConnection connection) {
-        // TODO: Do we need to handle the case of the original connection changing
-        // and triggering this callback multiple times for the same connection?
-        // If that is the case, we might want to remove this connection from all
-        // conference controllers first before re-adding it.
+        // TODO: Need to revisit what happens when the original connection for the
+        // TelephonyConnection changes.  If going from CDMA --> GSM (for example), the
+        // instance of TelephonyConnection will still be a CdmaConnection, not a GsmConnection.
+        // The CDMA conference controller makes the assumption that it will only have CDMA
+        // connections in it, while the other conference controllers aren't as restrictive.  Really,
+        // when we go between CDMA and GSM we should replace the TelephonyConnection.
         if (connection.isImsConnection()) {
             Log.d(this, "Adding IMS connection to conference controller: " + connection);
             mImsConferenceController.add(connection);
+            mTelephonyConferenceController.remove(connection);
+            if (connection instanceof CdmaConnection) {
+                mCdmaConferenceController.remove((CdmaConnection) connection);
+            }
         } else {
             int phoneType = connection.getCall().getPhone().getPhoneType();
             if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
                 Log.d(this, "Adding GSM connection to conference controller: " + connection);
                 mTelephonyConferenceController.add(connection);
+                if (connection instanceof CdmaConnection) {
+                    mCdmaConferenceController.remove((CdmaConnection) connection);
+                }
             } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA &&
                     connection instanceof CdmaConnection) {
                 Log.d(this, "Adding CDMA connection to conference controller: " + connection);
-                mCdmaConferenceController.add((CdmaConnection)connection);
+                mCdmaConferenceController.add((CdmaConnection) connection);
+                mTelephonyConferenceController.remove(connection);
             }
             Log.d(this, "Removing connection from IMS conference controller: " + connection);
             mImsConferenceController.remove(connection);