Merge "Show connection managers if any are present" into lmp-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index ed4e910..f668255 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -429,8 +429,8 @@
             <intent-filter>
                 <action android:name="android.intent.action.VIEW" />
                 <action android:name="android.intent.action.MAIN" />
-                <action android:name="android.telecomm.intent.action.SHOW_CALL_SETTINGS" />
-                <action android:name="android.telecomm.intent.action.CHANGE_PHONE_ACCOUNTS" />
+                <action android:name="android.telecomm.action.SHOW_CALL_SETTINGS" />
+                <action android:name="android.telecomm.action.CHANGE_PHONE_ACCOUNTS" />
                 <action android:name="com.android.phone.CallFeaturesSetting.ADD_VOICEMAIL" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
diff --git a/res/values/config.xml b/res/values/config.xml
index 0ced13f..3daf89a 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -120,8 +120,6 @@
     <bool name="config_enabled_lte" translatable="false">false</bool>
     <!-- Show cdma auto network mode in (glabal) roaming -->
     <bool name="config_show_cdma" translatable="false">false</bool>
-    <!-- Display enhanced 4G LTE mode menu if true -->
-    <bool name="config_enhanced_4g_lte_mode_enable" translatable="false">false</bool>
 
     <!-- Package name for the default in-call UI and dialer [DO NOT TRANSLATE] -->
     <string name="ui_default_package" translatable="false">com.android.dialer</string>
diff --git a/sip/src/com/android/services/telephony/sip/SipConnection.java b/sip/src/com/android/services/telephony/sip/SipConnection.java
index 534b27a..583fa0e 100644
--- a/sip/src/com/android/services/telephony/sip/SipConnection.java
+++ b/sip/src/com/android/services/telephony/sip/SipConnection.java
@@ -21,13 +21,13 @@
 import android.os.Message;
 import android.telecomm.AudioState;
 import android.telecomm.Connection;
+import android.telecomm.PhoneAccount;
 import android.telecomm.PhoneCapabilities;
 import android.util.Log;
 
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.sip.SipPhone;
-import com.android.phone.Constants;
 
 import java.util.List;
 import java.util.Objects;
@@ -307,7 +307,7 @@
         if (address == null) {
             address = "";
         }
-        return Uri.fromParts(Constants.SCHEME_SIP, address, null);
+        return Uri.fromParts(PhoneAccount.SCHEME_SIP, address, null);
     }
 
     private void close() {
diff --git a/sip/src/com/android/services/telephony/sip/SipUtil.java b/sip/src/com/android/services/telephony/sip/SipUtil.java
index 5733a18..e926fa1 100644
--- a/sip/src/com/android/services/telephony/sip/SipUtil.java
+++ b/sip/src/com/android/services/telephony/sip/SipUtil.java
@@ -32,8 +32,6 @@
             "com.android.services.telephony.sip.phone_account";
     static final String GATEWAY_PROVIDER_PACKAGE =
             "com.android.phone.extra.GATEWAY_PROVIDER_PACKAGE";
-    static final String SCHEME_TEL = "tel";
-    static final String SCHEME_SIP = "sip";
 
     private static boolean sIsVoipSupported;
     private static boolean sIsVoipSupportedInitialized;
diff --git a/src/com/android/phone/CallController.java b/src/com/android/phone/CallController.java
index a42f57d..a25b7a9 100644
--- a/src/com/android/phone/CallController.java
+++ b/src/com/android/phone/CallController.java
@@ -32,6 +32,7 @@
 import android.os.Message;
 import android.os.SystemProperties;
 import android.provider.CallLog.Calls;
+import android.telecomm.PhoneAccount;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.ServiceState;
 import android.util.Log;
@@ -466,7 +467,8 @@
                 //   app.cdmaOtaInCallScreenUiState.state are redundant.
                 //   Combine them.
 
-                boolean voicemailUriSpecified = scheme != null && scheme.equals("voicemail");
+                boolean voicemailUriSpecified = scheme != null &&
+                    scheme.equals(PhoneAccount.SCHEME_VOICEMAIL);
                 // Check for an obscure ECM-related scenario: If the phone
                 // is currently in ECM (Emergency callback mode) and we
                 // dial a non-emergency number, that automatically
diff --git a/src/com/android/phone/CallGatewayManager.java b/src/com/android/phone/CallGatewayManager.java
index 893070b..a349d17 100644
--- a/src/com/android/phone/CallGatewayManager.java
+++ b/src/com/android/phone/CallGatewayManager.java
@@ -18,6 +18,7 @@
 
 import android.content.Intent;
 import android.net.Uri;
+import android.telecomm.PhoneAccount;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 import android.util.Log;
@@ -185,7 +186,7 @@
      */
     public static String formatProviderUri(Uri uri) {
         if (uri != null) {
-            if (Constants.SCHEME_TEL.equals(uri.getScheme())) {
+            if (PhoneAccount.SCHEME_TEL.equals(uri.getScheme())) {
                 return PhoneNumberUtils.formatNumber(uri.getSchemeSpecificPart());
             } else {
                 return uri.toString();
diff --git a/src/com/android/phone/CallNotifier.java b/src/com/android/phone/CallNotifier.java
index 674f66d..0edf62f 100644
--- a/src/com/android/phone/CallNotifier.java
+++ b/src/com/android/phone/CallNotifier.java
@@ -25,7 +25,6 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.PhoneBase;
 import com.android.internal.telephony.TelephonyCapabilities;
-import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
 import com.android.internal.telephony.cdma.CdmaInformationRecords.CdmaDisplayInfoRec;
 import com.android.internal.telephony.cdma.CdmaInformationRecords.CdmaSignalInfoRec;
 import com.android.internal.telephony.cdma.SignalToneUtil;
@@ -71,12 +70,6 @@
     // before giving up and falling back to the default ringtone.
     private static final int RINGTONE_QUERY_WAIT_TIME = 500;  // msec
 
-    // Timers related to CDMA Call Waiting
-    // 1) For displaying Caller Info
-    // 2) For disabling "Add Call" menu option once User selects Ignore or CW Timeout occures
-    private static final int CALLWAITING_CALLERINFO_DISPLAY_TIME = 20000; // msec
-    private static final int CALLWAITING_ADDCALL_DISABLE_TIME = 30000; // msec
-
     // Time to display the  DisplayInfo Record sent by CDMA network
     private static final int DISPLAYINFO_NOTIFICATION_TIME = 2000; // msec
 
@@ -88,33 +81,6 @@
     /** The singleton instance. */
     private static CallNotifier sInstance;
 
-    // Boolean to keep track of whether or not a CDMA Call Waiting call timed out.
-    //
-    // This is CDMA-specific, because with CDMA we *don't* get explicit
-    // notification from the telephony layer that a call-waiting call has
-    // stopped ringing.  Instead, when a call-waiting call first comes in we
-    // start a 20-second timer (see CALLWAITING_CALLERINFO_DISPLAY_DONE), and
-    // if the timer expires we clean up the call and treat it as a missed call.
-    //
-    // If this field is true, that means that the current Call Waiting call
-    // "timed out" and should be logged in Call Log as a missed call.  If it's
-    // false when we reach onCdmaCallWaitingReject(), we can assume the user
-    // explicitly rejected this call-waiting call.
-    //
-    // This field is reset to false any time a call-waiting call first comes
-    // in, and after cleaning up a missed call-waiting call.  It's only ever
-    // set to true when the CALLWAITING_CALLERINFO_DISPLAY_DONE timer fires.
-    //
-    // TODO: do we really need a member variable for this?  Don't we always
-    // know at the moment we call onCdmaCallWaitingReject() whether this is an
-    // explicit rejection or not?
-    // (Specifically: when we call onCdmaCallWaitingReject() from
-    // PhoneUtils.hangupRingingCall() that means the user deliberately rejected
-    // the call, and if we call onCdmaCallWaitingReject() because of a
-    // CALLWAITING_CALLERINFO_DISPLAY_DONE event that means that it timed
-    // out...)
-    private boolean mCallWaitingTimeOut = false;
-
     // values used to track the query state
     private static final int CALLERINFO_QUERY_READY = 0;
     private static final int CALLERINFO_QUERYING = -1;
@@ -130,10 +96,7 @@
 
     // Events generated internally:
     private static final int PHONE_MWI_CHANGED = 21;
-    private static final int CALLWAITING_CALLERINFO_DISPLAY_DONE = 22;
-    private static final int CALLWAITING_ADDCALL_DISABLE_TIMEOUT = 23;
     private static final int DISPLAYINFO_NOTIFICATION_DONE = 24;
-    private static final int CDMA_CALL_WAITING_REJECT = 26;
     private static final int UPDATE_IN_CALL_NOTIFICATION = 27;
 
     // Emergency call related defines:
@@ -166,9 +129,6 @@
     // Ringback tone player
     private InCallTonePlayer mInCallRingbackTonePlayer;
 
-    // Call waiting tone player
-    private InCallTonePlayer mCallWaitingTonePlayer;
-
     // Cached AudioManager
     private AudioManager mAudioManager;
 
@@ -287,28 +247,6 @@
                 onMwiChanged(mApplication.phone.getMessageWaitingIndicator());
                 break;
 
-            case CallStateMonitor.PHONE_CDMA_CALL_WAITING:
-                if (DBG) log("Received PHONE_CDMA_CALL_WAITING event");
-                onCdmaCallWaiting((AsyncResult) msg.obj);
-                break;
-
-            case CDMA_CALL_WAITING_REJECT:
-                Log.i(LOG_TAG, "Received CDMA_CALL_WAITING_REJECT event");
-                onCdmaCallWaitingReject();
-                break;
-
-            case CALLWAITING_CALLERINFO_DISPLAY_DONE:
-                Log.i(LOG_TAG, "Received CALLWAITING_CALLERINFO_DISPLAY_DONE event");
-                mCallWaitingTimeOut = true;
-                onCdmaCallWaitingReject();
-                break;
-
-            case CALLWAITING_ADDCALL_DISABLE_TIMEOUT:
-                if (DBG) log("Received CALLWAITING_ADDCALL_DISABLE_TIMEOUT event ...");
-                // Set the mAddCallMenuStateAfterCW state to true
-                mApplication.cdmaPhoneCallState.setAddCallMenuStateAfterCallWaiting(true);
-                break;
-
             case CallStateMonitor.PHONE_STATE_DISPLAYINFO:
                 if (DBG) log("Received PHONE_STATE_DISPLAYINFO event");
                 onDisplayInfo((AsyncResult) msg.obj);
@@ -573,8 +511,6 @@
             // arrives at the same time that the query is still being run,
             // and before the timeout window has closed.
             EventLog.writeEvent(EventLogTags.PHONE_UI_MULTIPLE_QUERY);
-
-            ringAndNotifyOfIncomingCall(c);
         }
     }
 
@@ -628,14 +564,6 @@
             // Just bail out.
             return;
         }
-
-        // If the ringing call still does not have any connection anymore, do not send the
-        // notification.
-        final Call ringingCall = mCM.getFirstActiveRingingCall();
-
-        if (ringingCall != null && ringingCall.getLatestConnection() == c) {
-            ringAndNotifyOfIncomingCall(c);
-        }
     }
 
     private void onUnknownConnectionAppeared(AsyncResult r) {
@@ -649,23 +577,6 @@
     }
 
     /**
-     * If it is not a waiting call (there is no other active call in foreground), we will ring the
-     * ringtone. Otherwise we will play the call waiting tone instead.
-     * @param c The new ringing connection.
-     */
-    private void ringAndNotifyOfIncomingCall(Connection c) {
-        if (PhoneUtils.isRealIncomingCall(c.getState())) {
-            mRinger.ring();
-        } else {
-            if (VDBG) log("- starting call waiting tone...");
-            if (mCallWaitingTonePlayer == null) {
-                mCallWaitingTonePlayer = new InCallTonePlayer(InCallTonePlayer.TONE_CALL_WAITING);
-                mCallWaitingTonePlayer.start();
-            }
-        }
-    }
-
-    /**
      * Updates the phone UI in response to phone state changes.
      *
      * Watch out: certain state changes are actually handled by their own
@@ -709,11 +620,6 @@
         mApplication.updatePhoneState(state);
 
         if (state == PhoneConstants.State.OFFHOOK) {
-            // stop call waiting tone if needed when answering
-            if (mCallWaitingTonePlayer != null) {
-                mCallWaitingTonePlayer.stopTone();
-                mCallWaitingTonePlayer = null;
-            }
 
             if (VDBG) log("onPhoneStateChanged: OFF HOOK");
             // make sure audio is in in-call mode now
@@ -781,9 +687,6 @@
         // Clear ringback tone player
         mInCallRingbackTonePlayer = null;
 
-        // Clear call waiting tone player
-        mCallWaitingTonePlayer = null;
-
         // Instantiate mSignalInfoToneGenerator
         createSignalInfoToneGenerator();
     }
@@ -911,10 +814,6 @@
         if ((c != null) && (c.getCall().getPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA)) {
             // Resetting the CdmaPhoneCallState members
             mApplication.cdmaPhoneCallState.resetCdmaPhoneCallState();
-
-            // Remove Call waiting timers
-            removeMessages(CALLWAITING_CALLERINFO_DISPLAY_DONE);
-            removeMessages(CALLWAITING_ADDCALL_DISABLE_TIMEOUT);
         }
 
         // Stop the ringer if it was ringing (for an incoming call that
@@ -941,12 +840,6 @@
             mRinger.stopRing();
         }
 
-        // stop call waiting tone if needed when disconnecting
-        if (mCallWaitingTonePlayer != null) {
-            mCallWaitingTonePlayer.stopTone();
-            mCallWaitingTonePlayer = null;
-        }
-
         // If this is the end of an OTASP call, pass it on to the PhoneApp.
         if (c != null && TelephonyCapabilities.supportsOtasp(c.getCall().getPhone())) {
             final String number = c.getAddress();
@@ -1542,107 +1435,6 @@
     }
 
     /**
-     * Plays a Call waiting tone if it is present in the second incoming call.
-     */
-    private void onCdmaCallWaiting(AsyncResult r) {
-        // Remove any previous Call waiting timers in the queue
-        removeMessages(CALLWAITING_CALLERINFO_DISPLAY_DONE);
-        removeMessages(CALLWAITING_ADDCALL_DISABLE_TIMEOUT);
-
-        // Set the Phone Call State to SINGLE_ACTIVE as there is only one connection
-        // else we would not have received Call waiting
-        mApplication.cdmaPhoneCallState.setCurrentCallState(
-                CdmaPhoneCallState.PhoneCallState.SINGLE_ACTIVE);
-
-        // Start timer for CW display
-        mCallWaitingTimeOut = false;
-        sendEmptyMessageDelayed(CALLWAITING_CALLERINFO_DISPLAY_DONE,
-                CALLWAITING_CALLERINFO_DISPLAY_TIME);
-
-        // Set the mAddCallMenuStateAfterCW state to false
-        mApplication.cdmaPhoneCallState.setAddCallMenuStateAfterCallWaiting(false);
-
-        // Start the timer for disabling "Add Call" menu option
-        sendEmptyMessageDelayed(CALLWAITING_ADDCALL_DISABLE_TIMEOUT,
-                CALLWAITING_ADDCALL_DISABLE_TIME);
-
-        // Extract the Call waiting information
-        CdmaCallWaitingNotification infoCW = (CdmaCallWaitingNotification) r.result;
-        int isPresent = infoCW.isPresent;
-        if (DBG) log("onCdmaCallWaiting: isPresent=" + isPresent);
-        if (isPresent == 1 ) {//'1' if tone is valid
-            int uSignalType = infoCW.signalType;
-            int uAlertPitch = infoCW.alertPitch;
-            int uSignal = infoCW.signal;
-            if (DBG) log("onCdmaCallWaiting: uSignalType=" + uSignalType + ", uAlertPitch="
-                    + uAlertPitch + ", uSignal=" + uSignal);
-            //Map the Signal to a ToneGenerator ToneID only if Signal info is present
-            int toneID =
-                SignalToneUtil.getAudioToneFromSignalInfo(uSignalType, uAlertPitch, uSignal);
-
-            //Create the SignalInfo tone player and pass the ToneID
-            new SignalInfoTonePlayer(toneID).start();
-        }
-
-        // TODO: Remove this.
-        //mCallModeler.onCdmaCallWaiting(infoCW);
-    }
-
-    /**
-     * Posts a event causing us to clean up after rejecting (or timing-out) a
-     * CDMA call-waiting call.
-     *
-     * This method is safe to call from any thread.
-     * @see #onCdmaCallWaitingReject()
-     */
-    /* package */ void sendCdmaCallWaitingReject() {
-        sendEmptyMessage(CDMA_CALL_WAITING_REJECT);
-    }
-
-    /**
-     * Performs Call logging based on Timeout or Ignore Call Waiting Call for CDMA,
-     * and finally calls Hangup on the Call Waiting connection.
-     *
-     * This method should be called only from the UI thread.
-     * @see #sendCdmaCallWaitingReject()
-     */
-    private void onCdmaCallWaitingReject() {
-        final Call ringingCall = mCM.getFirstActiveRingingCall();
-
-        // Call waiting timeout scenario
-        if (ringingCall.getState() == Call.State.WAITING) {
-            // Code for perform Call logging and missed call notification
-            Connection c = ringingCall.getLatestConnection();
-
-            if (c != null) {
-                final int callLogType = mCallWaitingTimeOut ?
-                        Calls.MISSED_TYPE : Calls.INCOMING_TYPE;
-
-                // TODO: This callLogType override is not ideal. Connection should be astracted away
-                // at a telephony-phone layer that can understand and edit the callTypes within
-                // the abstraction for CDMA devices.
-                mCallLogger.logCall(c, callLogType);
-
-                if (callLogType != Calls.MISSED_TYPE) {
-                    // Remove Call waiting 20 second display timer in the queue
-                    removeMessages(CALLWAITING_CALLERINFO_DISPLAY_DONE);
-                }
-
-                // Hangup the RingingCall connection for CW
-                PhoneUtils.hangup(c);
-            }
-
-            //Reset the mCallWaitingTimeOut boolean
-            mCallWaitingTimeOut = false;
-        }
-
-        // Call modeler needs to know about this event regardless of the
-        // state conditionals in the previous code.
-        // TODO: Remove this.
-        //mCallModeler.onCdmaCallWaitingReject();
-    }
-
-    /**
      * Return the private variable mPreviousCdmaCallState.
      */
     /* package */ Call.State getPreviousCdmaCallState() {
diff --git a/src/com/android/phone/Constants.java b/src/com/android/phone/Constants.java
index 3e10c3a..79a1e9a 100644
--- a/src/com/android/phone/Constants.java
+++ b/src/com/android/phone/Constants.java
@@ -125,16 +125,6 @@
     }
 
     //
-    // URI schemes
-    //
-
-    public static final String SCHEME_SIP = "sip";
-    public static final String SCHEME_SMS = "sms";
-    public static final String SCHEME_SMSTO = "smsto";
-    public static final String SCHEME_TEL = "tel";
-    public static final String SCHEME_VOICEMAIL = "voicemail";
-
-    //
     // TODO: Move all the various EXTRA_* and intent action constants here too.
     // (Currently they're all over the place: InCallScreen,
     // OutgoingCallBroadcaster, OtaUtils, etc.)
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index bed49a9..ca42f2a 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -30,6 +30,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.Settings;
+import android.telecomm.PhoneAccount;
 import android.telephony.PhoneNumberUtils;
 import android.text.Editable;
 import android.text.TextUtils;
@@ -213,7 +214,7 @@
 
         // Extract phone number from intent
         Uri data = getIntent().getData();
-        if (data != null && (Constants.SCHEME_TEL.equals(data.getScheme()))) {
+        if (data != null && (PhoneAccount.SCHEME_TEL.equals(data.getScheme()))) {
             String number = PhoneNumberUtils.getNumberFromIntent(getIntent(), this);
             if (number != null) {
                 mDigits.setText(number);
@@ -520,7 +521,7 @@
                 return;
             }
             Intent intent = new Intent(Intent.ACTION_CALL_EMERGENCY);
-            intent.setData(Uri.fromParts(Constants.SCHEME_TEL, mLastNumber, null));
+            intent.setData(Uri.fromParts(PhoneAccount.SCHEME_TEL, mLastNumber, null));
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             startActivity(intent);
             finish();
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index 1806558..e6fc11c 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -330,22 +330,13 @@
             android.util.Log.d(LOG_TAG, "keep ltePref");
         }
 
-        // Enable enhanced 4G LTE mode settings depending on the value in config.xml
-        final boolean isEnhanced4GLteModeEnabled = getResources().getBoolean(
-                R.bool.config_enhanced_4g_lte_mode_enable);
-        if (!isEnhanced4GLteModeEnabled) {
+        // Enable enhanced 4G LTE mode settings depending on whether exists on platform
+        if (!ImsManager.isEnhanced4gLteModeSettingEnabledByPlatform(this)) {
             Preference pref = prefSet.findPreference(BUTTON_4G_LTE_KEY);
             if (pref != null) {
                 prefSet.removePreference(pref);
             }
         }
-        Preference pref = prefSet.findPreference(BUTTON_4G_LTE_KEY);
-        if (pref != null) {
-            if (!ImsManager.isEnhanced4gLteModeSettingEnabledByPlatform(this)) {
-                ((SwitchPreference)pref).setChecked(false);
-                pref.setEnabled(false);
-            }
-        }
 
         ActionBar actionBar = getActionBar();
         if (actionBar != null) {
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index 6650892..668038c 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -40,6 +40,7 @@
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.PhoneLookup;
 import android.provider.Settings;
+import android.telecomm.PhoneAccount;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.ServiceState;
 import android.text.BidiFormatter;
@@ -322,7 +323,7 @@
             }
 
             Intent intent = new Intent(Intent.ACTION_CALL,
-                    Uri.fromParts(Constants.SCHEME_VOICEMAIL, "", null));
+                    Uri.fromParts(PhoneAccount.SCHEME_VOICEMAIL, "", null));
             PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
 
             SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
diff --git a/src/com/android/phone/OtaUtils.java b/src/com/android/phone/OtaUtils.java
index fe11831..4a9154f 100644
--- a/src/com/android/phone/OtaUtils.java
+++ b/src/com/android/phone/OtaUtils.java
@@ -37,6 +37,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.telecomm.PhoneAccount;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -687,7 +688,7 @@
         if (!mApplication.cdmaOtaProvisionData.inOtaSpcState) {
             // Place an outgoing call to the special OTASP number:
             Intent newIntent = new Intent(Intent.ACTION_CALL);
-            newIntent.setData(Uri.fromParts(Constants.SCHEME_TEL, OTASP_NUMBER, null));
+            newIntent.setData(Uri.fromParts(PhoneAccount.SCHEME_TEL, OTASP_NUMBER, null));
 
             // Initiate the outgoing call:
             mApplication.callController.placeCall(newIntent);
diff --git a/src/com/android/phone/OutgoingCallBroadcaster.java b/src/com/android/phone/OutgoingCallBroadcaster.java
index 6d8830e..0f47c12 100644
--- a/src/com/android/phone/OutgoingCallBroadcaster.java
+++ b/src/com/android/phone/OutgoingCallBroadcaster.java
@@ -35,6 +35,7 @@
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.telecomm.PhoneAccount;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 import android.util.Log;
@@ -607,7 +608,7 @@
         // a plain address, whether it could be a tel: URI, etc.)
         Uri uri = intent.getData();
         String scheme = uri.getScheme();
-        if (Constants.SCHEME_SIP.equals(scheme) || PhoneNumberUtils.isUriNumber(number)) {
+        if (PhoneAccount.SCHEME_SIP.equals(scheme) || PhoneNumberUtils.isUriNumber(number)) {
             Log.i(TAG, "The requested number was detected as SIP call.");
             startSipCallOptionHandler(this, intent, uri, number);
             finish();
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 98db518..99cb206 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -113,14 +113,12 @@
     private static final int EVENT_SET_PREFERRED_NETWORK_TYPE_DONE = 24;
     private static final int CMD_SEND_ENVELOPE = 25;
     private static final int EVENT_SEND_ENVELOPE_DONE = 26;
-    private static final int CMD_SET_CDMA_SUBSCRIPTION = 27;
-    private static final int EVENT_SET_CDMA_SUBSCRIPTION_DONE = 28;
-    private static final int CMD_INVOKE_OEM_RIL_REQUEST_RAW = 29;
-    private static final int EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE = 30;
-    private static final int CMD_TRANSMIT_APDU_BASIC_CHANNEL = 31;
-    private static final int EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE = 32;
-    private static final int CMD_EXCHANGE_SIM_IO = 33;
-    private static final int EVENT_EXCHANGE_SIM_IO_DONE = 34;
+    private static final int CMD_INVOKE_OEM_RIL_REQUEST_RAW = 27;
+    private static final int EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE = 28;
+    private static final int CMD_TRANSMIT_APDU_BASIC_CHANNEL = 29;
+    private static final int EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE = 30;
+    private static final int CMD_EXCHANGE_SIM_IO = 31;
+    private static final int EVENT_EXCHANGE_SIM_IO_DONE = 32;
 
     /** The singleton instance. */
     private static PhoneInterfaceManager sInstance;
@@ -582,17 +580,6 @@
                     handleNullReturnEvent(msg, "setPreferredNetworkType");
                     break;
 
-                case CMD_SET_CDMA_SUBSCRIPTION:
-                    request = (MainThreadRequest) msg.obj;
-                    onCompleted = obtainMessage(EVENT_SET_CDMA_SUBSCRIPTION_DONE, request);
-                    int subscriptionType = (Integer) request.argument;
-                    mPhone.setCdmaSubscription(subscriptionType, onCompleted);
-                    break;
-
-                case EVENT_SET_CDMA_SUBSCRIPTION_DONE:
-                    handleNullReturnEvent(msg, "setCdmaSubscription");
-                    break;
-
                 case CMD_INVOKE_OEM_RIL_REQUEST_RAW:
                     request = (MainThreadRequest)msg.obj;
                     onCompleted = obtainMessage(EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE, request);
@@ -1878,31 +1865,6 @@
     }
 
     /**
-     * Set the CDMA subscription source.
-     * Used for device supporting both NV and RUIM for CDMA.
-     *
-     * @param subscriptionType the subscription type, 0 for RUIM, 1 for NV.
-     * @return true on success; false on any failure.
-     */
-    @Override
-    public boolean setCdmaSubscription(int subscriptionType) {
-        enforceModifyPermissionOrCarrierPrivilege();
-        if (DBG) log("setCdmaSubscription: type " + subscriptionType);
-        if (subscriptionType != mPhone.CDMA_SUBSCRIPTION_RUIM_SIM &&
-            subscriptionType != mPhone.CDMA_SUBSCRIPTION_NV) {
-           loge("setCdmaSubscription: unsupported subscriptionType.");
-           return false;
-        }
-        Boolean success = (Boolean) sendRequest(CMD_SET_CDMA_SUBSCRIPTION, subscriptionType);
-        if (DBG) log("setCdmaSubscription: " + (success ? "ok" : "fail"));
-        if (success) {
-            Settings.Global.putInt(mPhone.getContext().getContentResolver(),
-                    Settings.Global.CDMA_SUBSCRIPTION_MODE, subscriptionType);
-        }
-        return success;
-    }
-
-    /**
      * Set mobile data enabled
      * Used by the user through settings etc to turn on/off mobile data
      *
@@ -2016,9 +1978,9 @@
     }
 
     @Override
-    public boolean setOperatorBrandOverride(String iccId, String brand) {
+    public boolean setOperatorBrandOverride(String brand) {
         enforceModifyPermissionOrCarrierPrivilege();
-        return mPhone.setOperatorBrandOverride(iccId, brand);
+        return mPhone.setOperatorBrandOverride(brand);
     }
 
     @Override
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index ae40087..2b864cc 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -33,6 +33,7 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.SystemProperties;
+import android.telecomm.PhoneAccount;
 import android.telecomm.VideoProfile;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
@@ -367,27 +368,6 @@
             // Regular incoming call (with no other active calls)
             log("hangupRingingCall(): regular incoming call: hangup()");
             return hangup(ringing);
-        } else if (state == Call.State.WAITING) {
-            // Call-waiting: there's an incoming call, but another call is
-            // already active.
-            // TODO: It would be better for the telephony layer to provide
-            // a "hangupWaitingCall()" API that works on all devices,
-            // rather than us having to check the phone type here and do
-            // the notifier.sendCdmaCallWaitingReject() hack for CDMA phones.
-            if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
-                // CDMA: Ringing call and Call waiting hangup is handled differently.
-                // For Call waiting we DO NOT call the conventional hangup(call) function
-                // as in CDMA we just want to hangup the Call waiting connection.
-                log("hangupRingingCall(): CDMA-specific call-waiting hangup");
-                final CallNotifier notifier = PhoneGlobals.getInstance().notifier;
-                notifier.sendCdmaCallWaitingReject();
-                return true;
-            } else {
-                // Otherwise, the regular hangup() API works for
-                // call-waiting calls too.
-                log("hangupRingingCall(): call-waiting call: hangup()");
-                return hangup(ringing);
-            }
         } else {
             // Unexpected state: the ringing call isn't INCOMING or
             // WAITING, so there's no reason to have called
@@ -618,7 +598,7 @@
         if (useGateway) {
             // TODO: 'tel' should be a constant defined in framework base
             // somewhere (it is in webkit.)
-            if (null == gatewayUri || !Constants.SCHEME_TEL.equals(gatewayUri.getScheme())) {
+            if (null == gatewayUri || !PhoneAccount.SCHEME_TEL.equals(gatewayUri.getScheme())) {
                 Log.e(LOG_TAG, "Unsupported URL:" + gatewayUri);
                 return CALL_STATUS_FAILED;
             }
@@ -1255,7 +1235,7 @@
 
         // The sip: scheme is simple: just treat the rest of the URI as a
         // SIP address.
-        if (Constants.SCHEME_SIP.equals(scheme)) {
+        if (PhoneAccount.SCHEME_SIP.equals(scheme)) {
             return uri.getSchemeSpecificPart();
         }
 
@@ -1266,7 +1246,7 @@
 
         // Check for a voicemail-dialing request.  If the voicemail number is
         // empty, throw a VoiceMailNumberMissingException.
-        if (Constants.SCHEME_VOICEMAIL.equals(scheme) &&
+        if (PhoneAccount.SCHEME_VOICEMAIL.equals(scheme) &&
                 (number == null || TextUtils.isEmpty(number)))
             throw new VoiceMailNumberMissingException();
 
diff --git a/src/com/android/phone/SimContacts.java b/src/com/android/phone/SimContacts.java
index bebb6ea..cc2b992 100644
--- a/src/com/android/phone/SimContacts.java
+++ b/src/com/android/phone/SimContacts.java
@@ -38,6 +38,7 @@
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
 import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.RawContacts;
+import android.telecomm.PhoneAccount;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.ContextMenu;
@@ -345,7 +346,7 @@
                         return true;
                     }
                     Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
-                            Uri.fromParts(Constants.SCHEME_TEL, phoneNumber, null));
+                            Uri.fromParts(PhoneAccount.SCHEME_TEL, phoneNumber, null));
                     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                                           | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                     startActivity(intent);
diff --git a/src/com/android/services/telephony/CdmaConference.java b/src/com/android/services/telephony/CdmaConference.java
new file mode 100644
index 0000000..90f8566
--- /dev/null
+++ b/src/com/android/services/telephony/CdmaConference.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.services.telephony;
+
+import android.telecomm.Conference;
+import android.telecomm.Connection;
+import android.telecomm.PhoneAccountHandle;
+import android.telecomm.PhoneCapabilities;
+
+import com.android.internal.telephony.Call;
+import com.android.internal.telephony.CallStateException;
+
+import java.util.List;
+
+/**
+ * CDMA-based conference call.
+ */
+public class CdmaConference extends Conference {
+
+    private int mCapabilities =
+            PhoneCapabilities.MUTE |
+            PhoneCapabilities.MERGE_CONFERENCE;
+
+    public CdmaConference(PhoneAccountHandle phoneAccount) {
+        super(phoneAccount);
+        updateCapabilities();
+        setActive();
+    }
+
+    private void updateCapabilities() {
+        setCapabilities(mCapabilities);
+    }
+    /**
+     * Invoked when the Conference and all it's {@link Connection}s should be disconnected.
+     */
+    @Override
+    public void onDisconnect() {
+        Call call = getOriginalCall();
+        if (call != null) {
+            Log.d(this, "Found multiparty call to hangup for conference.");
+            try {
+                call.hangup();
+            } catch (CallStateException e) {
+                Log.e(this, e, "Exception thrown trying to hangup conference");
+            }
+        }
+    }
+
+    @Override
+    public void onSeparate(Connection connection) {
+        Log.e(this, new Exception(), "Separate not supported for CDMA conference call.");
+    }
+
+    @Override
+    public void onHold() {
+        Log.e(this, new Exception(), "Hold not supported for CDMA conference call.");
+    }
+
+    /**
+     * Invoked when the conference should be moved from hold to active.
+     */
+    @Override
+    public void onUnhold() {
+        Log.e(this, new Exception(), "Unhold not supported for CDMA conference call.");
+    }
+
+    @Override
+    public void onMerge() {
+        Log.i(this, "Merging CDMA conference call.");
+        // Can only merge once
+        mCapabilities &= ~PhoneCapabilities.MERGE_CONFERENCE;
+        // Once merged, swap is enabled.
+        mCapabilities |= PhoneCapabilities.SWAP_CONFERENCE;
+        updateCapabilities();
+        sendFlash();
+    }
+
+    @Override
+    public void onSwap() {
+        Log.i(this, "Swapping CDMA conference call.");
+        sendFlash();
+    }
+
+    private void sendFlash() {
+        Call call = getOriginalCall();
+        if (call != null) {
+            try {
+                // For CDMA calls, this just sends a flash command.
+                call.getPhone().switchHoldingAndActive();
+            } catch (CallStateException e) {
+                Log.e(this, e, "Error while trying to send flash command.");
+            }
+        }
+    }
+
+    private Call getMultipartyCallForConnection(Connection connection) {
+        com.android.internal.telephony.Connection radioConnection =
+                getOriginalConnection(connection);
+        if (radioConnection != null) {
+            Call call = radioConnection.getCall();
+            if (call != null && call.isMultiparty()) {
+                return call;
+            }
+        }
+        return null;
+    }
+
+    private Call getOriginalCall() {
+        List<Connection> connections = getConnections();
+        if (!connections.isEmpty()) {
+            com.android.internal.telephony.Connection originalConnection =
+                    getOriginalConnection(connections.get(0));
+            if (originalConnection != null) {
+                return originalConnection.getCall();
+            }
+        }
+        return null;
+    }
+
+    private com.android.internal.telephony.Connection getOriginalConnection(Connection connection) {
+        if (connection instanceof CdmaConnection) {
+            return ((CdmaConnection) connection).getOriginalConnection();
+        } else {
+            Log.e(this, null, "Non CDMA connection found in a CDMA conference");
+            return null;
+        }
+    }
+}
diff --git a/src/com/android/services/telephony/CdmaConferenceController.java b/src/com/android/services/telephony/CdmaConferenceController.java
new file mode 100644
index 0000000..e3a0981
--- /dev/null
+++ b/src/com/android/services/telephony/CdmaConferenceController.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.services.telephony;
+
+import android.os.Handler;
+import android.telecomm.Connection;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Manages CDMA conference calls. CDMA conference calls are much more limited than GSM conference
+ * calls. Two main points of difference:
+ * 1) Users cannot manage individual calls within a conference
+ * 2) Whether a conference call starts off as a conference or as two distinct calls is a matter of
+ *    physical location (some antennas are different than others). Worst still, there's no
+ *    indication given to us as to what state they are in.
+ *
+ * To make life easier on the user we do the following: Whenever there exist 2 or more calls, we
+ * say that we are in a conference call with {@link Connection#CAPABILITY_GENERIC_CONFERENCE}.
+ * Generic indicates that this is a simple conference that doesn't support conference management.
+ * The conference call will also support "MERGE" to begin with and stop supporting it the first time
+ * we are asked to actually execute a merge. I emphasize when "we are asked" because we get no
+ * indication whether the merge succeeds from CDMA, we just assume it does. Thats the best we
+ * can do. Also, we do not kill a conference call once it is created unless all underlying
+ * connections also go away.
+ *
+ * Outgoing CDMA calls made while another call exists would normally trigger a conference to be
+ * created. To avoid this and make it seem like there is a "dialing" state, we fake it and prevent
+ * the conference from being created for 3 seconds. This is a more pleasant experience for the user.
+ */
+final class CdmaConferenceController {
+    private final Connection.Listener mConnectionListener = new Connection.Listener() {
+                @Override
+                public void onStateChanged(Connection c, int state) {
+                    recalculateConference();
+                }
+
+                @Override
+                public void onDisconnected(Connection c, int cause, String message) {
+                    recalculateConference();
+                }
+
+                @Override
+                public void onDestroyed(Connection c) {
+                    remove((CdmaConnection) c);
+                }
+            };
+
+    private static final int ADD_OUTGOING_CONNECTION_DELAY_MILLIS = 6000;
+
+    /** The known CDMA connections. */
+    private final List<CdmaConnection> mCdmaConnections = new ArrayList<>();
+
+    /**
+     * Newly added connections.  We keep track of newly added outgoing connections because we do not
+     * create a conference until a second outgoing call has existing for
+     * {@link #ADD_OUTGOING_CONNECTION_DELAY_MILLIS} milliseconds.  This allows the UI to show the
+     * call as "Dialing" for a certain amount of seconds.
+     */
+    private final List<CdmaConnection> mPendingOutgoingConnections = new ArrayList<>();
+
+    private final TelephonyConnectionService mConnectionService;
+
+    private final Handler mHandler = new Handler();
+
+    public CdmaConferenceController(TelephonyConnectionService connectionService) {
+        mConnectionService = connectionService;
+    }
+
+    /** The CDMA conference connection object. */
+    private CdmaConference mConference;
+
+    void add(final CdmaConnection connection) {
+        if (!mCdmaConnections.isEmpty() && connection.isOutgoing()) {
+            connection.forceAsDialing(true);
+            // There already exists a connection, so this will probably result in a conference once
+            // it is added. For connections which are added while another connection exists, we
+            // mark them as "dialing" for set amount of time to give the user time to see their
+            // new call as "Dialing" before it turns into a conference call.
+            mHandler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    connection.forceAsDialing(false);
+                    addInternal(connection);
+                }
+            }, ADD_OUTGOING_CONNECTION_DELAY_MILLIS);
+        } else {
+            // This is the first connection, or it is incoming, so let it flow through.
+            addInternal(connection);
+        }
+    }
+
+    private void addInternal(CdmaConnection connection) {
+        mCdmaConnections.add(connection);
+        connection.addConnectionListener(mConnectionListener);
+        recalculateConference();
+    }
+
+    private void remove(CdmaConnection connection) {
+        connection.removeConnectionListener(mConnectionListener);
+        mCdmaConnections.remove(connection);
+        recalculateConference();
+    }
+
+    private void recalculateConference() {
+        List<CdmaConnection> conferenceConnections = new ArrayList<>(mCdmaConnections.size());
+        for (CdmaConnection connection : mCdmaConnections) {
+            // We do not include call-waiting calls in conferences.
+            if (!connection.isCallWaiting() &&
+                    connection.getState() != Connection.STATE_DISCONNECTED) {
+                conferenceConnections.add(connection);
+            }
+        }
+
+        Log.d(this, "recalculating conference calls %d", conferenceConnections.size());
+        if (conferenceConnections.size() >= 2) {
+            boolean isNewlyCreated = false;
+
+            // There are two or more CDMA connections. Do the following:
+            // 1) Create a new conference connection if it doesn't exist.
+            if (mConference == null) {
+                Log.i(this, "Creating new Cdma conference call");
+                mConference = new CdmaConference(null);
+                isNewlyCreated = true;
+            }
+
+            // 2) Add any new connections to the conference
+            List<Connection> existingChildConnections =
+                    new ArrayList<>(mConference.getConnections());
+            for (CdmaConnection connection : conferenceConnections) {
+                if (!existingChildConnections.contains(connection)) {
+                    Log.i(this, "Adding connection to conference call: %s", connection);
+                    mConference.addConnection(connection);
+                }
+                existingChildConnections.remove(connection);
+            }
+
+            // 3) Remove any lingering old/disconnected/destroyed connections
+            for (Connection oldConnection : existingChildConnections) {
+                mConference.removeConnection(oldConnection);
+                Log.i(this, "Removing connection from conference call: %s", oldConnection);
+            }
+
+            // 4) Add the conference to the connection service if it is new.
+            if (isNewlyCreated) {
+                Log.d(this, "Adding the conference call");
+                mConnectionService.addConference(mConference);
+            }
+        } else if (conferenceConnections.isEmpty()) {
+            // There are no more connection so if we still have a conference, lets remove it.
+            if (mConference != null) {
+                Log.i(this, "Destroying the CDMA conference connection.");
+                mConference.destroy();
+            }
+        }
+    }
+}
diff --git a/src/com/android/services/telephony/CdmaConnection.java b/src/com/android/services/telephony/CdmaConnection.java
index 67104b5..12ccbce 100644
--- a/src/com/android/services/telephony/CdmaConnection.java
+++ b/src/com/android/services/telephony/CdmaConnection.java
@@ -16,8 +16,14 @@
 
 package com.android.services.telephony;
 
+import android.os.Handler;
+import android.os.Message;
 import android.telecomm.PhoneCapabilities;
 
+import android.telephony.DisconnectCause;
+
+import com.android.internal.telephony.Call;
+import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.Connection;
 
 /**
@@ -25,14 +31,41 @@
  */
 final class CdmaConnection extends TelephonyConnection {
 
+    private static final int MSG_CALL_WAITING_MISSED = 1;
+    private static final int TIMEOUT_CALL_WAITING_MILLIS = 20 * 1000;
+
+    private final Handler mHandler = new Handler() {
+
+        /** ${inheritDoc} */
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_CALL_WAITING_MISSED:
+                    hangupCallWaiting(DisconnectCause.INCOMING_MISSED);
+                    break;
+                default:
+                    break;
+            }
+        }
+
+    };
+
     /**
      * {@code True} if the CDMA connection should allow mute.
      */
     private final boolean mAllowMute;
+    private final boolean mIsOutgoing;
 
-    CdmaConnection(Connection connection, boolean allowMute) {
+    private boolean mIsCallWaiting;
+
+    CdmaConnection(Connection connection, boolean allowMute, boolean isOutgoing) {
         super(connection);
         mAllowMute = allowMute;
+        mIsOutgoing = isOutgoing;
+        mIsCallWaiting = connection != null && connection.getState() == Call.State.WAITING;
+        if (mIsCallWaiting) {
+            startCallWaitingTimer();
+        }
     }
 
     /** {@inheritDoc} */
@@ -55,6 +88,41 @@
     }
 
     @Override
+    public void onReject() {
+        Connection connection = getOriginalConnection();
+        if (connection != null) {
+            switch (connection.getState()) {
+                case INCOMING:
+                    // Normal ringing calls are handled the generic way.
+                    super.onReject();
+                    break;
+                case WAITING:
+                    hangupCallWaiting(DisconnectCause.INCOMING_REJECTED);
+                    break;
+                default:
+                    Log.e(this, new Exception(), "Rejecting a non-ringing call");
+                    // might as well hang this up, too.
+                    super.onReject();
+                    break;
+            }
+        }
+    }
+
+    @Override
+    public void onAnswer() {
+        mHandler.removeMessages(MSG_CALL_WAITING_MISSED);
+        super.onAnswer();
+    }
+
+    @Override
+    public void onSetState(int state) {
+        Connection originalConnection = getOriginalConnection();
+        mIsCallWaiting = originalConnection != null &&
+                originalConnection.getState() == Call.State.WAITING;
+        super.onSetState(state);
+    }
+
+    @Override
     protected int buildCallCapabilities() {
         int capabilities = 0;
         if (mAllowMute) {
@@ -62,4 +130,42 @@
         }
         return capabilities;
     }
+
+    void forceAsDialing(boolean isDialing) {
+        if (isDialing) {
+            setDialing();
+        } else {
+            updateState();
+        }
+    }
+
+    boolean isOutgoing() {
+        return mIsOutgoing;
+    }
+
+    boolean isCallWaiting() {
+        return mIsCallWaiting;
+    }
+
+    /**
+     * We do not get much in the way of confirmation for Cdma call waiting calls. There is no
+     * indication that a rejected call succeeded, a call waiting call has stopped. Instead we
+     * simulate this for the user. We allow TIMEOUT_CALL_WAITING_MILLIS milliseconds before we
+     * assume that the call was missed and reject it ourselves. reject the call automatically.
+     */
+    private void startCallWaitingTimer() {
+        mHandler.sendEmptyMessageDelayed(MSG_CALL_WAITING_MISSED, TIMEOUT_CALL_WAITING_MILLIS);
+    }
+
+    private void hangupCallWaiting(int disconnectCause) {
+        Connection originalConnection = getOriginalConnection();
+        if (originalConnection != null) {
+            try {
+                originalConnection.hangup();
+            } catch (CallStateException e) {
+                Log.e(this, e, "Failed to hangup call waiting call");
+            }
+            setDisconnected(disconnectCause, null);
+        }
+    }
 }
diff --git a/src/com/android/services/telephony/GsmConference.java b/src/com/android/services/telephony/GsmConference.java
index a45b896..00e46fa 100644
--- a/src/com/android/services/telephony/GsmConference.java
+++ b/src/com/android/services/telephony/GsmConference.java
@@ -37,7 +37,7 @@
                 PhoneCapabilities.SUPPORT_HOLD |
                 PhoneCapabilities.HOLD |
                 PhoneCapabilities.MUTE |
-                PhoneCapabilities.SWAP_CALLS);
+                PhoneCapabilities.MANAGE_CONFERENCE);
         setActive();
     }
 
diff --git a/src/com/android/services/telephony/GsmConnection.java b/src/com/android/services/telephony/GsmConnection.java
index 99f2cde..ecd851e 100644
--- a/src/com/android/services/telephony/GsmConnection.java
+++ b/src/com/android/services/telephony/GsmConnection.java
@@ -25,8 +25,6 @@
  * Manages a single phone call handled by GSM.
  */
 final class GsmConnection extends TelephonyConnection {
-    private boolean mIsConferenceCapable;
-
     GsmConnection(Connection connection) {
         super(connection);
     }
@@ -47,13 +45,6 @@
         }
     }
 
-    void setIsConferenceCapable(boolean isConferenceCapable) {
-        if (mIsConferenceCapable != isConferenceCapable) {
-            mIsConferenceCapable = isConferenceCapable;
-            updateCallCapabilities();
-        }
-    }
-
     @Override
     public void performConference(TelephonyConnection otherConnection) {
         Log.d(this, "performConference - %s", this);
@@ -77,9 +68,6 @@
         if (getState() == STATE_ACTIVE || getState() == STATE_HOLDING) {
             capabilities |= PhoneCapabilities.HOLD;
         }
-        if (mIsConferenceCapable) {
-            capabilities |= PhoneCapabilities.MERGE_CALLS;
-        }
         return capabilities;
     }
 
diff --git a/src/com/android/services/telephony/PstnIncomingCallNotifier.java b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
index f64dedf..73bc3a9 100644
--- a/src/com/android/services/telephony/PstnIncomingCallNotifier.java
+++ b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
@@ -33,8 +33,11 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.PhoneProxy;
 import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
 import com.google.common.base.Preconditions;
 
+import java.util.Objects;
+
 /**
  * Listens to incoming-call events from the associated phone object and notifies Telecomm upon each
  * occurence. One instance of these exists for each of the telephony-based call services.
@@ -42,6 +45,7 @@
 final class PstnIncomingCallNotifier {
     /** New ringing connection event code. */
     private static final int EVENT_NEW_RINGING_CONNECTION = 100;
+    private static final int EVENT_CDMA_CALL_WAITING = 101;
 
     /** The phone proxy object to listen to. */
     private final PhoneProxy mPhoneProxy;
@@ -64,6 +68,9 @@
                 case EVENT_NEW_RINGING_CONNECTION:
                     handleNewRingingConnection((AsyncResult) msg.obj);
                     break;
+                case EVENT_CDMA_CALL_WAITING:
+                    handleCdmaCallWaiting((AsyncResult) msg.obj);
+                    break;
                 default:
                     break;
             }
@@ -121,23 +128,24 @@
     private void registerForNotifications() {
         Phone newPhone = mPhoneProxy.getActivePhone();
         if (newPhone != mPhoneBase) {
-            if (mPhoneBase != null) {
-                Log.i(this, "Unregistering: %s", mPhoneBase);
-                mPhoneBase.unregisterForNewRingingConnection(mHandler);
-            }
+            unregisterForNotifications();
 
             if (newPhone != null) {
                 Log.i(this, "Registering: %s", newPhone);
                 mPhoneBase = newPhone;
                 mPhoneBase.registerForNewRingingConnection(
                         mHandler, EVENT_NEW_RINGING_CONNECTION, null);
+                mPhoneBase.registerForCallWaiting(
+                        mHandler, EVENT_CDMA_CALL_WAITING, null);
             }
         }
     }
 
     private void unregisterForNotifications() {
         if (mPhoneBase != null) {
+            Log.i(this, "Unregistering: %s", mPhoneBase);
             mPhoneBase.unregisterForNewRingingConnection(mHandler);
+            mPhoneBase.unregisterForCallWaiting(mHandler);
         }
     }
 
@@ -159,6 +167,21 @@
         }
     }
 
+    private void handleCdmaCallWaiting(AsyncResult asyncResult) {
+        Log.d(this, "handleCdmaCallWaiting");
+        CdmaCallWaitingNotification ccwi = (CdmaCallWaitingNotification) asyncResult.result;
+        Call call = mPhoneBase.getRingingCall();
+        if (call.getState() == Call.State.WAITING) {
+            Connection connection = call.getLatestConnection();
+            if (connection != null) {
+                String number = connection.getAddress();
+                if (number != null && Objects.equals(number, ccwi.number)) {
+                    sendIncomingCallIntent(connection);
+                }
+            }
+        }
+    }
+
     /**
      * Sends the incoming call intent to telecomm.
      */
diff --git a/src/com/android/services/telephony/TelecommAccountRegistry.java b/src/com/android/services/telephony/TelecommAccountRegistry.java
index 095073b..1eaf6e1 100644
--- a/src/com/android/services/telephony/TelecommAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecommAccountRegistry.java
@@ -97,7 +97,7 @@
                     : dummyPrefix + "SIM card in slot " + slotId;
             PhoneAccount account = PhoneAccount.builder()
                     .withAccountHandle(phoneAccountHandle)
-                    .withHandle(Uri.fromParts(TEL_SCHEME, line1Number, null))
+                    .withHandle(Uri.fromParts(PhoneAccount.SCHEME_TEL, line1Number, null))
                     .withSubscriptionNumber(subNumber)
                     .withCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
                             PhoneAccount.CAPABILITY_CALL_PROVIDER)
@@ -132,8 +132,6 @@
         }
     };
 
-    private static final String TEL_SCHEME = "tel";
-    private static final String VOICEMAIL_SCHEME = "voicemail";
     private static TelecommAccountRegistry sInstance;
     private final Context mContext;
     private final TelecommManager mTelecommManager;
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 9cbf8a6..60e5d17 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -22,6 +22,7 @@
 import android.os.Message;
 import android.telecomm.AudioState;
 import android.telecomm.Connection;
+import android.telecomm.PhoneAccount;
 import android.telecomm.PhoneCapabilities;
 import android.telephony.DisconnectCause;
 
@@ -222,9 +223,6 @@
     @Override
     public void onAnswer(int videoState) {
         Log.v(this, "onAnswer");
-        // TODO: Tons of hairy logic is missing here around multiple active calls on
-        // CDMA devices. See {@link CallManager.acceptCall}.
-
         if (isValidRingingCall() && getPhone() != null) {
             try {
                 getPhone().acceptCall(videoState);
@@ -390,7 +388,7 @@
         updateHandle();
     }
 
-    private void hangup(int disconnectCause) {
+    protected void hangup(int disconnectCause) {
         if (mOriginalConnection != null) {
             try {
                 // Hanging up a ringing call requires that we invoke call.hangup() as opposed to
@@ -490,7 +488,7 @@
         return true;
     }
 
-    private void updateState() {
+    protected void updateState() {
         if (mOriginalConnection == null) {
             return;
         }
@@ -642,7 +640,7 @@
         if (address == null) {
             address = "";
         }
-        return Uri.fromParts(TelephonyConnectionService.SCHEME_TEL, address, null);
+        return Uri.fromParts(PhoneAccount.SCHEME_TEL, address, null);
     }
 
     /**
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index f77666a..5d96665 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -20,11 +20,10 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.telecomm.Connection;
-import android.telecomm.PhoneCapabilities;
 import android.telecomm.ConnectionRequest;
 import android.telecomm.ConnectionService;
+import android.telecomm.PhoneAccount;
 import android.telecomm.PhoneAccountHandle;
-import android.telecomm.Response;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.ServiceState;
@@ -47,11 +46,10 @@
  * Service for making GSM and CDMA connections.
  */
 public class TelephonyConnectionService extends ConnectionService {
-    static String SCHEME_TEL = "tel";
-    static String SCHEME_VOICEMAIL = "voicemail";
-
     private final GsmConferenceController mGsmConferenceController =
             new GsmConferenceController(this);
+    private final CdmaConferenceController mCdmaConferenceController =
+            new CdmaConferenceController(this);
     private ComponentName mExpectedComponentName = null;
     private EmergencyCallHelper mEmergencyCallHelper;
 
@@ -65,7 +63,7 @@
     public Connection onCreateOutgoingConnection(
             PhoneAccountHandle connectionManagerPhoneAccount,
             final ConnectionRequest request) {
-        Log.v(this, "onCreateOutgoingConnection, request: " + request);
+        Log.i(this, "onCreateOutgoingConnection, request: " + request);
 
         Uri handle = request.getHandle();
         if (handle == null) {
@@ -76,7 +74,7 @@
 
         String scheme = handle.getScheme();
         final String number;
-        if (SCHEME_VOICEMAIL.equals(scheme)) {
+        if (PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
             // TODO: We don't check for SecurityException here (requires
             // CALL_PRIVILEGED permission).
             final Phone phone = getPhoneForAccount(request.getAccountHandle(), false);
@@ -88,9 +86,9 @@
             }
 
             // Convert voicemail: to tel:
-            handle = Uri.fromParts(SCHEME_TEL, number, null);
+            handle = Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null);
         } else {
-            if (!SCHEME_TEL.equals(scheme)) {
+            if (!PhoneAccount.SCHEME_TEL.equals(scheme)) {
                 Log.d(this, "onCreateOutgoingConnection, Handle %s is not type tel", scheme);
                 return Connection.createFailedConnection(DisconnectCause.INVALID_NUMBER,
                         "Handle scheme is not type tel");
@@ -139,7 +137,8 @@
             }
         }
 
-        final TelephonyConnection connection = createConnectionFor(phone, null);
+        final TelephonyConnection connection =
+                createConnectionFor(phone, null, true /* isOutgoing */);
         if (connection == null) {
             return Connection.createFailedConnection(
                     DisconnectCause.OUTGOING_FAILURE, "Invalid phone type");
@@ -181,7 +180,7 @@
     public Connection onCreateIncomingConnection(
             PhoneAccountHandle connectionManagerPhoneAccount,
             ConnectionRequest request) {
-        Log.v(this, "onCreateIncomingConnection, request: " + request);
+        Log.i(this, "onCreateIncomingConnection, request: " + request);
 
         Phone phone = getPhoneForAccount(request.getAccountHandle(), false);
         if (phone == null) {
@@ -190,18 +189,21 @@
 
         Call call = phone.getRingingCall();
         if (!call.getState().isRinging()) {
-            Log.v(this, "onCreateIncomingConnection, no ringing call");
+            Log.i(this, "onCreateIncomingConnection, no ringing call");
             return Connection.createFailedConnection(DisconnectCause.INCOMING_MISSED,
                     "Found no ringing call");
         }
 
-        com.android.internal.telephony.Connection originalConnection = call.getEarliestConnection();
+        com.android.internal.telephony.Connection originalConnection =
+                call.getState() == Call.State.WAITING ?
+                    call.getLatestConnection() : call.getEarliestConnection();
         if (isOriginalConnectionKnown(originalConnection)) {
-            Log.v(this, "onCreateIncomingConnection, original connection already registered");
+            Log.i(this, "onCreateIncomingConnection, original connection already registered");
             return Connection.createCanceledConnection();
         }
 
-        Connection connection = createConnectionFor(phone, originalConnection);
+        Connection connection =
+                createConnectionFor(phone, originalConnection, false /* isOutgoing */);
         if (connection == null) {
             connection = Connection.createCanceledConnection();
             return Connection.createCanceledConnection();
@@ -253,7 +255,9 @@
     }
 
     private TelephonyConnection createConnectionFor(
-            Phone phone, com.android.internal.telephony.Connection originalConnection) {
+            Phone phone,
+            com.android.internal.telephony.Connection originalConnection,
+            boolean isOutgoing) {
         int phoneType = phone.getPhoneType();
         if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
             GsmConnection connection = new GsmConnection(originalConnection);
@@ -261,7 +265,10 @@
             return connection;
         } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
             boolean allowMute = allowMute(phone);
-            return new CdmaConnection(originalConnection, allowMute);
+            CdmaConnection connection =
+                    new CdmaConnection(originalConnection, allowMute, isOutgoing);
+            mCdmaConferenceController.add(connection);
+            return connection;
         } else {
             return null;
         }
diff --git a/tests/src/com/android/phone/tests/CallDialTest.java b/tests/src/com/android/phone/tests/CallDialTest.java
index 5ea80d1..baade32 100644
--- a/tests/src/com/android/phone/tests/CallDialTest.java
+++ b/tests/src/com/android/phone/tests/CallDialTest.java
@@ -23,6 +23,7 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.telecomm.PhoneAccount;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 import android.util.Log;
@@ -125,9 +126,9 @@
             if (number.contains(":")) {
                 uri = Uri.parse(number);
             } else if (PhoneNumberUtils.isUriNumber(number)) {
-                uri = Uri.fromParts(Constants.SCHEME_SIP, number, null);
+                uri = Uri.fromParts(PhoneAccount.SCHEME_SIP, number, null);
             } else {
-                uri = Uri.fromParts(Constants.SCHEME_TEL, number, null);
+                uri = Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null);
             }
         }
         log("==> uri: " + uri);