Merge "Reorganize phone account settings." into lmp-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 09c3aae..e779771 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -511,12 +511,6 @@
                 android:configChanges="orientation|screenSize|keyboardHidden"
                 android:uiOptions="splitActionBarWhenNarrow">
         </activity>
-        <activity android:name="com.android.services.telephony.sip.SipProfileChooserDialogs"
-                android:theme="@style/SipCallOptionHandlerTheme"
-                android:screenOrientation="nosensor"
-                android:configChanges="orientation|screenSize|keyboardHidden"
-                android:excludeFromRecents="true">
-        </activity>
 
         <!-- End SIP -->
 
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 291cfc5..bc77128 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -277,10 +277,6 @@
         <item name="*android:windowAnimationStyle">@style/OutgoingAnimationStyle</item>
     </style>
 
-    <style name="SipCallOptionHandlerTheme" parent="@android:style/Theme.Holo.NoActionBar">
-        <item name="android:windowBackground">@android:color/black</item>
-    </style>
-
     <style name="DialtactsDigitsTextAppearance">
         <item name="android:maxLines">1</item>
         <item name="android:textSize">@dimen/dialpad_digits_text_size</item>
diff --git a/sip/res/values/array.xml b/sip/res/values/array.xml
index 02940e8..1f33204 100644
--- a/sip/res/values/array.xml
+++ b/sip/res/values/array.xml
@@ -36,11 +36,6 @@
         <item>@string/sip_address_only</item>
     </string-array>
 
-    <string-array translatable="false" name="phone_type_values">
-        <item>@string/pstn_phone</item>
-        <item>@string/internet_phone</item>
-    </string-array>
-
     <string-array translatable="true" name="sip_send_keepalive_options">
         <item>@string/sip_system_decide</item>
         <item>@string/sip_always_send_keepalive</item>
diff --git a/sip/res/values/strings.xml b/sip/res/values/strings.xml
index 0163a31..b220d17 100644
--- a/sip/res/values/strings.xml
+++ b/sip/res/values/strings.xml
@@ -38,31 +38,6 @@
     <!-- Item of the SIP call (Wi-Fi only) option dialog: for routing all outgoing calls via SIP. [CHAR LIMIT=NONE] -->
     <string name="sip_call_options_wifi_only_entry_1">For all calls</string>
 
-    <!-- Title of the dialog to select the phone type for the outgoing call. [CHAR LIMIT=NONE] -->
-    <string name ="pick_outgoing_call_phone_type">Place call</string>
-
-    <!-- Title of the dialog to select the phone among the list of phones for the outgoing call. [CHAR LIMIT=NONE] -->
-    <string name ="pick_outgoing_sip_phone">Use SIP account:</string>
-
-    <!-- Text of checkbox to remember the sip phone for all outbound calls. [CHAR LIMIT=NONE] -->
-    <string name ="remember_my_choice">Always use to place SIP calls</string>
-
-    <!-- Help text of checkbox to unset the default sip phone for all outbound calls. [CHAR LIMIT=NONE] -->
-    <string name ="reset_my_choice_hint">You can change which SIP account to use by default from the Phone &gt; Settings &gt; SIP call settings &gt; Accounts screen.</string>
-
-    <!-- Item of the dialog to select the phone type for outgoing call. [CHAR LIMIT=NONE] -->
-    <string name ="pstn_phone">Cell phone call</string>
-
-    <!-- Item of the dialog to select the phone type for outgoing call. [CHAR LIMIT=NONE] -->
-    <string name ="internet_phone">SIP call</string>
-
-    <!-- Title of the dialog to redirect the user to SIP settings. [CHAR LIMIT=NONE] -->
-    <string name ="no_sip_account_found_title">No SIP account</string>
-    <!-- Message of the dialog to redirect the user to SIP settings. [CHAR LIMIT=NONE] -->
-    <string name ="no_sip_account_found">There are no SIP accounts on this phone. Do you want to add one now?</string>
-    <!-- Menu item for no sip account found dialog -->
-    <string name="sip_menu_add">Add</string>
-
     <!-- Title for the button to add a new sip account. [CHAR LIMIT=NONE] -->
     <string name="add_sip_account">Add account</string>
     <!-- Title for the button to remove a sip account. [CHAR LIMIT=NONE] -->
@@ -163,15 +138,11 @@
     <!-- Showing that port number is out of range in an alert dialog. [CHAR LIMIT=NONE] -->
     <string name="not_a_valid_port">Port number should be within 1000 and 65534.</string>
 
-    <!-- Title of the alert dialog to notify user that there is no Internet connectivity. [CHAR LIMIT=40] -->
-    <string name="no_internet_available_title">No Internet connection</string>
-    <!-- Title of the alert dialog to notify user that there is no Wi-Fi connectivity. [CHAR LIMIT=40] -->
-    <string name="no_wifi_available_title">No Wi-Fi connection</string>
     <!-- Message of the alert dialog to notify user that there is no Internet connectivity. [CHAR LIMIT=NONE] -->
     <string name="no_internet_available">To place a SIP call, check your Internet connection first.</string>
     <!-- Message of the alert dialog to notify user that there is no Wi-Fi connectivity. [CHAR LIMIT=NONE] -->
     <string name="no_wifi_available">You need to be connected to a Wi-Fi network for SIP calls (use the Wireless &amp; Network settings).</string>
-    <!-- Title of the alert dialog to notify user that SIP call is not supported. [CHAR LIMIT=40] -->
+    <!-- Message of the alert dialog to notify user that SIP call is not supported. [CHAR LIMIT=NONE] -->
     <string name="no_voip">SIP calling not supported</string>
 
     <!-- Option for whether the SIP service should send keepalive messages. [CHAR LIMIT=40] -->
diff --git a/sip/src/com/android/services/telephony/sip/SipConnectionService.java b/sip/src/com/android/services/telephony/sip/SipConnectionService.java
index a53a336..ae21d73 100644
--- a/sip/src/com/android/services/telephony/sip/SipConnectionService.java
+++ b/sip/src/com/android/services/telephony/sip/SipConnectionService.java
@@ -89,25 +89,21 @@
         boolean attemptCall = true;
 
         if (!SipUtil.isVoipSupported(this)) {
-            SipProfileChooserDialogs.showNoVoip(this, new ResultReceiver(mHandler) {
-                    @Override
-                    protected void onReceiveResult(int choice, Bundle resultData) {
-                        connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
-                                DisconnectCause.ERROR_UNSPECIFIED, "VoIP unsupported"));
-                    }
-            });
+            final CharSequence description = getString(R.string.no_voip);
+            connection.setDisconnected(new android.telecom.DisconnectCause(
+                    android.telecom.DisconnectCause.ERROR, null, description,
+                    "VoIP unsupported"));
             attemptCall = false;
         }
 
         if (attemptCall && !isNetworkConnected()) {
             if (VERBOSE) log("start, network not connected, dropping call");
-            SipProfileChooserDialogs.showNoInternetError(this, new ResultReceiver(mHandler) {
-                    @Override
-                    protected void onReceiveResult(int choice, Bundle resultData) {
-                        connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
-                                DisconnectCause.OUT_OF_SERVICE, "Network not connected."));
-                    }
-            });
+            final boolean wifiOnly = SipManager.isSipWifiOnly(this);
+            final CharSequence description = getString(wifiOnly ? R.string.no_wifi_available
+                    : R.string.no_internet_available);
+            connection.setDisconnected(new android.telecom.DisconnectCause(
+                    android.telecom.DisconnectCause.ERROR, null, description,
+                    "Network not connected"));
             attemptCall = false;
         }
 
diff --git a/sip/src/com/android/services/telephony/sip/SipProfileChooserDialogs.java b/sip/src/com/android/services/telephony/sip/SipProfileChooserDialogs.java
deleted file mode 100644
index 4eb9762..0000000
--- a/sip/src/com/android/services/telephony/sip/SipProfileChooserDialogs.java
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * 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.sip;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.net.sip.SipManager;
-import android.net.sip.SipProfile;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.ResultReceiver;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.TextView;
-
-import java.util.List;
-
-public final class SipProfileChooserDialogs extends Activity
-        implements DialogInterface.OnClickListener,
-        DialogInterface.OnCancelListener, CompoundButton.OnCheckedChangeListener {
-    private static final String PREFIX = "[SipProfileChooserDialogs] ";
-    private static final boolean VERBOSE = false; /* STOP SHIP if true */
-
-    private static final String EXTRA_RESULT_RECEIVER = "result_receiver";
-    private static final String EXTRA_DIALOG_ID = "dialog_id";
-    private static final String EXTRA_PROFILE_NAMES = "profile_names";
-    private static final String EXTRA_MAKE_PRIMARY = "make_primary";
-
-    private static final int DIALOG_SELECT_PHONE_TYPE = 0;
-    private static final int DIALOG_SELECT_PROFILE = 1;
-    private static final int DIALOG_START_SIP_SETTINGS = 2;
-    private static final int DIALOG_NO_INTERNET_ERROR = 3;
-    private static final int DIALOG_NO_VOIP = 4;
-
-    private TextView mUnsetPriamryHint;
-    private boolean mMakePrimary;
-
-    static void showSelectPhoneType(Context context, ResultReceiver resultReceiver) {
-        show(context, DIALOG_SELECT_PHONE_TYPE, null, resultReceiver);
-    }
-
-    static void showSelectProfile(Context context, List<SipProfile> profiles,
-            ResultReceiver resultReceiver) {
-        show(context, DIALOG_SELECT_PROFILE, profiles, resultReceiver);
-    }
-
-    static void showStartSipSettings(Context context, ResultReceiver resultReceiver) {
-        show(context, DIALOG_START_SIP_SETTINGS, null, resultReceiver);
-    }
-
-    static void showNoInternetError(Context context, ResultReceiver resultReceiver) {
-        show(context, DIALOG_NO_INTERNET_ERROR, null, resultReceiver);
-    }
-
-    static void showNoVoip(Context context, ResultReceiver resultReceiver) {
-        show(context, DIALOG_NO_VOIP, null, resultReceiver);
-    }
-
-    static boolean isSelectedPhoneTypeSip(Context context, int choice) {
-        String[] phoneTypes = context.getResources().getStringArray(R.array.phone_type_values);
-        if (choice >= 0 && choice < phoneTypes.length) {
-            return phoneTypes[choice].equals(context.getString(R.string.internet_phone));
-        }
-        return false;
-    }
-
-    static boolean shouldMakeSelectedProflePrimary(Context context, Bundle extras) {
-        return extras.getBoolean(EXTRA_MAKE_PRIMARY);
-    }
-
-    static private void show(final Context context, final int dialogId,
-            final List<SipProfile> profiles,
-            final ResultReceiver resultReceiver) {
-        if (VERBOSE) log("show, starting delayed show, dialogId: " + dialogId);
-
-        // Wait for 1 second before showing the dialog. The sometimes prevents the InCallUI from
-        // popping up on top of the dialog. See http://b/16184268
-        new Handler().postDelayed(new Runnable() {
-            @Override
-            public void run() {
-                if (VERBOSE) log("show, starting activity");
-                Intent intent = new Intent(context, SipProfileChooserDialogs.class)
-                        .putExtra(EXTRA_RESULT_RECEIVER, resultReceiver)
-                        .putExtra(EXTRA_DIALOG_ID, dialogId)
-                        .putExtra(EXTRA_PROFILE_NAMES, getProfileNames(profiles))
-                        .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-                context.startActivity(intent);
-            }
-        }, 1000);
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        int dialogId = getIntent().getIntExtra(EXTRA_DIALOG_ID, 0);
-        if (VERBOSE) log("onCreate, dialogId: " + dialogId);
-
-        // Allow this activity to be visible in front of the keyguard. (This is only necessary for
-        // obscure scenarios like the user initiating a call and then immediately pressing the Power
-        // button.)
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
-
-        showDialog(dialogId);
-    }
-
-    @Override
-    protected Dialog onCreateDialog(int id, Bundle args) {
-        Dialog dialog;
-        switch(id) {
-            case DIALOG_SELECT_PHONE_TYPE:
-                dialog = new AlertDialog.Builder(this)
-                        .setTitle(R.string.pick_outgoing_call_phone_type)
-                        .setIconAttribute(android.R.attr.alertDialogIcon)
-                        .setSingleChoiceItems(R.array.phone_type_values, -1, this)
-                        .setNegativeButton(android.R.string.cancel, this)
-                        .setOnCancelListener(this)
-                        .create();
-                break;
-            case DIALOG_SELECT_PROFILE:
-                String[] profileNames = getIntent().getStringArrayExtra(EXTRA_PROFILE_NAMES);
-                dialog = new AlertDialog.Builder(this)
-                        .setTitle(R.string.pick_outgoing_sip_phone)
-                        .setIconAttribute(android.R.attr.alertDialogIcon)
-                        .setSingleChoiceItems(profileNames, -1, this)
-                        .setNegativeButton(android.R.string.cancel, this)
-                        .setOnCancelListener(this)
-                        .create();
-                addMakeDefaultCheckBox(dialog);
-                break;
-            case DIALOG_START_SIP_SETTINGS:
-                dialog = new AlertDialog.Builder(this)
-                        .setTitle(R.string.no_sip_account_found_title)
-                        .setMessage(R.string.no_sip_account_found)
-                        .setIconAttribute(android.R.attr.alertDialogIcon)
-                        .setPositiveButton(R.string.sip_menu_add, this)
-                        .setNegativeButton(android.R.string.cancel, this)
-                        .setOnCancelListener(this)
-                        .create();
-                break;
-            case DIALOG_NO_INTERNET_ERROR:
-                boolean wifiOnly = SipManager.isSipWifiOnly(this);
-                dialog = new AlertDialog.Builder(this)
-                        .setTitle(wifiOnly ? R.string.no_wifi_available_title
-                                           : R.string.no_internet_available_title)
-                        .setMessage(wifiOnly ? R.string.no_wifi_available
-                                             : R.string.no_internet_available)
-                        .setIconAttribute(android.R.attr.alertDialogIcon)
-                        .setPositiveButton(android.R.string.ok, this)
-                        .setOnCancelListener(this)
-                        .create();
-                break;
-            case DIALOG_NO_VOIP:
-                dialog = new AlertDialog.Builder(this)
-                        .setTitle(R.string.no_voip)
-                        .setIconAttribute(android.R.attr.alertDialogIcon)
-                        .setPositiveButton(android.R.string.ok, this)
-                        .setOnCancelListener(this)
-                        .create();
-                break;
-            default:
-                dialog = null;
-        }
-        if (dialog != null) {
-            //mDialogs[id] = dialog;
-        }
-        return dialog;
-    }
-
-    @Override
-    protected void onPause() {
-        super.onPause();
-        if (VERBOSE) log("onPause");
-    }
-
-    @Override
-    public void finish() {
-        if (VERBOSE) log("finish");
-        super.finish();
-    }
-
-    @Override
-    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-        if (VERBOSE) log("onCheckedChanged, isChecked: " + isChecked);
-        mMakePrimary = isChecked;
-        if (isChecked) {
-            mUnsetPriamryHint.setVisibility(View.VISIBLE);
-        } else {
-            mUnsetPriamryHint.setVisibility(View.INVISIBLE);
-        }
-    }
-
-    @Override
-    public void onClick(DialogInterface dialog, int id) {
-        if (VERBOSE) log("onClick, id: " + id);
-        onChoiceMade(id);
-    }
-
-    @Override
-    public void onCancel(DialogInterface dialog) {
-        if (VERBOSE) log("onCancel");
-        onChoiceMade(DialogInterface.BUTTON_NEGATIVE);
-    }
-
-    private void onChoiceMade(int choice) {
-        ResultReceiver resultReceiver = getIntent().getParcelableExtra(EXTRA_RESULT_RECEIVER);
-        if (resultReceiver != null) {
-            Bundle extras = new Bundle();
-            extras.putBoolean(EXTRA_MAKE_PRIMARY, mMakePrimary);
-            resultReceiver.send(choice, extras);
-        }
-        finish();
-    }
-
-    private void addMakeDefaultCheckBox(Dialog dialog) {
-        LayoutInflater inflater = (LayoutInflater) getSystemService(
-                Context.LAYOUT_INFLATER_SERVICE);
-        View view = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
-        CheckBox makePrimaryCheckBox =
-                (CheckBox) view.findViewById(com.android.internal.R.id.alwaysUse);
-        makePrimaryCheckBox.setText(R.string.remember_my_choice);
-        makePrimaryCheckBox.setOnCheckedChangeListener(this);
-        mUnsetPriamryHint = (TextView)view.findViewById(com.android.internal.R.id.clearDefaultHint);
-        mUnsetPriamryHint.setText(R.string.reset_my_choice_hint);
-        mUnsetPriamryHint.setVisibility(View.GONE);
-        ((AlertDialog)dialog).setView(view);
-    }
-
-    static private String[] getProfileNames(List<SipProfile> profiles) {
-        if (profiles == null) {
-            return null;
-        }
-
-        String[] entries = new String[profiles.size()];
-        int i = 0;
-        for (SipProfile p : profiles) {
-            entries[i++] = p.getProfileName();
-        }
-        return entries;
-    }
-
-    private static void log(String msg) {
-        Log.d(SipUtil.LOG_TAG, PREFIX + msg);
-    }
-}
diff --git a/src/com/android/phone/CallNotifier.java b/src/com/android/phone/CallNotifier.java
index 5380fa5..be1e3b2 100644
--- a/src/com/android/phone/CallNotifier.java
+++ b/src/com/android/phone/CallNotifier.java
@@ -91,10 +91,6 @@
     private static final int DISPLAYINFO_NOTIFICATION_DONE = 24;
     private static final int UPDATE_IN_CALL_NOTIFICATION = 27;
 
-    // Emergency call related defines:
-    private static final int EMERGENCY_TONE_OFF = 0;
-    private static final int EMERGENCY_TONE_ALERT = 1;
-    private static final int EMERGENCY_TONE_VIBRATE = 2;
 
     private PhoneGlobals mApplication;
     private CallManager mCM;
@@ -111,14 +107,6 @@
     private boolean mVoicePrivacyState = false;
     private boolean mIsCdmaRedialCall = false;
 
-    // Emergency call tone and vibrate:
-    private int mIsEmergencyToneOn;
-    private int mCurrentEmergencyToneState = EMERGENCY_TONE_OFF;
-    private EmergencyTonePlayerVibrator mEmergencyTonePlayerVibrator;
-
-    // Ringback tone player
-    private InCallTonePlayer mInCallRingbackTonePlayer;
-
     // Cached AudioManager
     private AudioManager mAudioManager;
 
@@ -253,11 +241,6 @@
                 }
                 break;
 
-            case CallStateMonitor.PHONE_RINGBACK_TONE:
-                // DISABLED. The Telecom and new ConnectionService layers are now responsible.
-                // onRingbackTone((AsyncResult) msg.obj);
-                break;
-
             default:
                 // super.handleMessage(msg);
         }
@@ -481,59 +464,11 @@
             // make sure audio is in in-call mode now
             PhoneUtils.setAudioMode(mCM);
         }
-
-        if (fgPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
-            Connection c = fgPhone.getForegroundCall().getLatestConnection();
-            if ((c != null) && (PhoneNumberUtils.isLocalEmergencyNumber(mApplication,
-                                                                        c.getAddress()))) {
-                if (VDBG) log("onPhoneStateChanged: it is an emergency call.");
-                Call.State callState = fgPhone.getForegroundCall().getState();
-                if (mEmergencyTonePlayerVibrator == null) {
-                    mEmergencyTonePlayerVibrator = new EmergencyTonePlayerVibrator();
-                }
-
-                if (callState == Call.State.DIALING || callState == Call.State.ALERTING) {
-                    mIsEmergencyToneOn = Settings.Global.getInt(
-                            mApplication.getContentResolver(),
-                            Settings.Global.EMERGENCY_TONE, EMERGENCY_TONE_OFF);
-                    if (mIsEmergencyToneOn != EMERGENCY_TONE_OFF &&
-                        mCurrentEmergencyToneState == EMERGENCY_TONE_OFF) {
-                        if (mEmergencyTonePlayerVibrator != null) {
-                            mEmergencyTonePlayerVibrator.start();
-                        }
-                    }
-                } else if (callState == Call.State.ACTIVE) {
-                    if (mCurrentEmergencyToneState != EMERGENCY_TONE_OFF) {
-                        if (mEmergencyTonePlayerVibrator != null) {
-                            mEmergencyTonePlayerVibrator.stop();
-                        }
-                    }
-                }
-            }
-        }
-
-        if (fgPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM
-                || fgPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_SIP
-                || fgPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS
-                || fgPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_THIRD_PARTY) {
-            Call.State callState = mCM.getActiveFgCallState();
-            if (!callState.isDialing()) {
-                // If call gets activated or disconnected before the ringback
-                // tone stops, we have to stop it to prevent disturbing.
-                if (mInCallRingbackTonePlayer != null) {
-                    mInCallRingbackTonePlayer.stopTone();
-                    mInCallRingbackTonePlayer = null;
-                }
-            }
-        }
     }
 
     void updateCallNotifierRegistrationsAfterRadioTechnologyChange() {
         if (DBG) Log.d(LOG_TAG, "updateCallNotifierRegistrationsAfterRadioTechnologyChange...");
 
-        // Clear ringback tone player
-        mInCallRingbackTonePlayer = null;
-
         // Instantiate mSignalInfoToneGenerator
         createSignalInfoToneGenerator();
     }
@@ -614,15 +549,6 @@
             final boolean isEmergencyNumber =
                     PhoneNumberUtils.isLocalEmergencyNumber(mApplication, number);
 
-            if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
-                if ((isEmergencyNumber)
-                        && (mCurrentEmergencyToneState != EMERGENCY_TONE_OFF)) {
-                    if (mEmergencyTonePlayerVibrator != null) {
-                        mEmergencyTonePlayerVibrator.stop();
-                    }
-                }
-            }
-
             // Possibly play a "post-disconnect tone" thru the earpiece.
             // We do this here, rather than from the InCallScreen
             // activity, since we need to do this even if you're not in
@@ -750,7 +676,6 @@
         public static final int TONE_OUT_OF_SERVICE = 9;
         public static final int TONE_REDIAL = 10;
         public static final int TONE_OTA_CALL_END = 11;
-        public static final int TONE_RING_BACK = 12;
         public static final int TONE_UNOBTAINABLE_NUMBER = 13;
 
         // The tone volume relative to other sounds in the stream
@@ -855,12 +780,6 @@
                     toneVolume = TONE_RELATIVE_VOLUME_LOPRI;
                     toneLengthMillis = 5000;
                     break;
-                case TONE_RING_BACK:
-                    toneType = ToneGenerator.TONE_SUP_RINGTONE;
-                    toneVolume = TONE_RELATIVE_VOLUME_HIPRI;
-                    // Call ring back tone is stopped by stopTone() method
-                    toneLengthMillis = Integer.MAX_VALUE - TONE_TIMEOUT_BUFFER;
-                    break;
                 case TONE_UNOBTAINABLE_NUMBER:
                     toneType = ToneGenerator.TONE_SUP_ERROR;
                     toneVolume = TONE_RELATIVE_VOLUME_HIPRI;
@@ -1107,78 +1026,7 @@
         return mIsCdmaRedialCall;
     }
 
-    /**
-     *  Inner class to handle emergency call tone and vibrator
-     */
-    private class EmergencyTonePlayerVibrator {
-        private final int EMG_VIBRATE_LENGTH = 1000;  // ms.
-        private final int EMG_VIBRATE_PAUSE  = 1000;  // ms.
-        private final long[] mVibratePattern =
-                new long[] { EMG_VIBRATE_LENGTH, EMG_VIBRATE_PAUSE };
-
-        private ToneGenerator mToneGenerator;
-        // We don't rely on getSystemService(Context.VIBRATOR_SERVICE) to make sure this vibrator
-        // object will be isolated from others.
-        private Vibrator mEmgVibrator = new SystemVibrator();
-        private int mInCallVolume;
-
-        /**
-         * constructor
-         */
-        public EmergencyTonePlayerVibrator() {
-        }
-
-        /**
-         * Start the emergency tone or vibrator.
-         */
-        private void start() {
-            if (VDBG) log("call startEmergencyToneOrVibrate.");
-            int ringerMode = mAudioManager.getRingerMode();
-
-            if ((mIsEmergencyToneOn == EMERGENCY_TONE_ALERT) &&
-                    (ringerMode == AudioManager.RINGER_MODE_NORMAL)) {
-                log("EmergencyTonePlayerVibrator.start(): emergency tone...");
-                mToneGenerator = new ToneGenerator (AudioManager.STREAM_VOICE_CALL,
-                        InCallTonePlayer.TONE_RELATIVE_VOLUME_EMERGENCY);
-                if (mToneGenerator != null) {
-                    mInCallVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
-                    mAudioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL,
-                            mAudioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL),
-                            0);
-                    mToneGenerator.startTone(ToneGenerator.TONE_CDMA_EMERGENCY_RINGBACK);
-                    mCurrentEmergencyToneState = EMERGENCY_TONE_ALERT;
-                }
-            } else if (mIsEmergencyToneOn == EMERGENCY_TONE_VIBRATE) {
-                log("EmergencyTonePlayerVibrator.start(): emergency vibrate...");
-                if (mEmgVibrator != null) {
-                    mEmgVibrator.vibrate(mVibratePattern, 0, VIBRATION_ATTRIBUTES);
-                    mCurrentEmergencyToneState = EMERGENCY_TONE_VIBRATE;
-                }
-            }
-        }
-
-        /**
-         * If the emergency tone is active, stop the tone or vibrator accordingly.
-         */
-        private void stop() {
-            if (VDBG) log("call stopEmergencyToneOrVibrate.");
-
-            if ((mCurrentEmergencyToneState == EMERGENCY_TONE_ALERT)
-                    && (mToneGenerator != null)) {
-                mToneGenerator.stopTone();
-                mToneGenerator.release();
-                mAudioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL,
-                        mInCallVolume,
-                        0);
-            } else if ((mCurrentEmergencyToneState == EMERGENCY_TONE_VIBRATE)
-                    && (mEmgVibrator != null)) {
-                mEmgVibrator.cancel();
-            }
-            mCurrentEmergencyToneState = EMERGENCY_TONE_OFF;
-        }
-    }
-
-     private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
+    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
         new BluetoothProfile.ServiceListener() {
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
             mBluetoothHeadset = (BluetoothHeadset) proxy;
@@ -1190,27 +1038,6 @@
         }
     };
 
-    private void onRingbackTone(AsyncResult r) {
-        boolean playTone = (Boolean)(r.result);
-
-        if (playTone == true) {
-            // Only play when foreground call is in DIALING or ALERTING.
-            // to prevent a late coming playtone after ALERTING.
-            // Don't play ringback tone if it is in play, otherwise it will cut
-            // the current tone and replay it
-            if (mCM.getActiveFgCallState().isDialing() &&
-                mInCallRingbackTonePlayer == null) {
-                mInCallRingbackTonePlayer = new InCallTonePlayer(InCallTonePlayer.TONE_RING_BACK);
-                mInCallRingbackTonePlayer.start();
-            }
-        } else {
-            if (mInCallRingbackTonePlayer != null) {
-                mInCallRingbackTonePlayer.stopTone();
-                mInCallRingbackTonePlayer = null;
-            }
-        }
-    }
-
     private void log(String msg) {
         Log.d(LOG_TAG, msg);
     }
diff --git a/src/com/android/services/telephony/CdmaConference.java b/src/com/android/services/telephony/CdmaConference.java
index e0fa41a..c77557f 100644
--- a/src/com/android/services/telephony/CdmaConference.java
+++ b/src/com/android/services/telephony/CdmaConference.java
@@ -31,13 +31,11 @@
  */
 public class CdmaConference extends Conference {
 
-    private int mCapabilities =
-            PhoneCapabilities.MUTE |
-            PhoneCapabilities.MERGE_CONFERENCE;
+    private int mCapabilities = PhoneCapabilities.MUTE;
 
-    public CdmaConference(PhoneAccountHandle phoneAccount) {
+    public CdmaConference(PhoneAccountHandle phoneAccount, int capabilities) {
         super(phoneAccount);
-        updateCapabilities();
+        setCapabilities(mCapabilities | capabilities);
         setActive();
     }
 
diff --git a/src/com/android/services/telephony/CdmaConferenceController.java b/src/com/android/services/telephony/CdmaConferenceController.java
index 19b0430..ab126ca 100644
--- a/src/com/android/services/telephony/CdmaConferenceController.java
+++ b/src/com/android/services/telephony/CdmaConferenceController.java
@@ -19,6 +19,7 @@
 import android.os.Handler;
 import android.telecom.Connection;
 import android.telecom.DisconnectCause;
+import android.telecom.PhoneCapabilities;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -136,7 +137,15 @@
             // 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);
+                CdmaConnection newConnection = mCdmaConnections.get(mCdmaConnections.size() - 1);
+                if (newConnection.isOutgoing()) {
+                    // Only an outgoing call can be merged with an ongoing call.
+                    mConference = new CdmaConference(null, PhoneCapabilities.MERGE_CONFERENCE);
+                } else {
+                    // If the most recently added connection was an incoming call, enable
+                    // swap instead of merge.
+                    mConference = new CdmaConference(null, PhoneCapabilities.SWAP_CONFERENCE);
+                }
                 isNewlyCreated = true;
             }
 
diff --git a/src/com/android/services/telephony/CdmaConnection.java b/src/com/android/services/telephony/CdmaConnection.java
index a56205a..5d470ab 100644
--- a/src/com/android/services/telephony/CdmaConnection.java
+++ b/src/com/android/services/telephony/CdmaConnection.java
@@ -22,10 +22,12 @@
 import android.provider.Settings;
 import android.telecom.PhoneCapabilities;
 import android.telephony.DisconnectCause;
+import android.telephony.PhoneNumberUtils;
 
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.Connection;
+import com.android.internal.telephony.Phone;
 import com.android.phone.Constants;
 
 import java.util.LinkedList;
@@ -66,13 +68,20 @@
     private final boolean mIsOutgoing;
     // Queue of pending short-DTMF characters.
     private final Queue<Character> mDtmfQueue = new LinkedList<>();
+    private final EmergencyTonePlayer mEmergencyTonePlayer;
 
     // Indicates that the DTMF confirmation from telephony is pending.
     private boolean mDtmfBurstConfirmationPending = false;
     private boolean mIsCallWaiting;
 
-    CdmaConnection(Connection connection, boolean allowMute, boolean isOutgoing) {
+    CdmaConnection(
+            Connection connection,
+            EmergencyTonePlayer emergencyTonePlayer,
+            boolean allowMute,
+            boolean isOutgoing) {
+
         super(connection);
+        mEmergencyTonePlayer = emergencyTonePlayer;
         mAllowMute = allowMute;
         mIsOutgoing = isOutgoing;
         mIsCallWaiting = connection != null && connection.getState() == Call.State.WAITING;
@@ -133,6 +142,16 @@
         Connection originalConnection = getOriginalConnection();
         mIsCallWaiting = originalConnection != null &&
                 originalConnection.getState() == Call.State.WAITING;
+
+        if (state == android.telecom.Connection.STATE_DIALING) {
+            if (isEmergency()) {
+                mEmergencyTonePlayer.start();
+            }
+        } else {
+            // No need to check if it is an emergency call, since it is a no-op if it isn't started.
+            mEmergencyTonePlayer.stop();
+        }
+
         super.onStateChanged(state);
     }
 
@@ -231,4 +250,11 @@
             }
         }
     }
+
+    private boolean isEmergency() {
+        Phone phone = getPhone();
+        return phone != null &&
+                PhoneNumberUtils.isLocalEmergencyNumber(
+                    phone.getContext(), getAddress().getSchemeSpecificPart());
+    }
 }
diff --git a/src/com/android/services/telephony/EmergencyTonePlayer.java b/src/com/android/services/telephony/EmergencyTonePlayer.java
new file mode 100644
index 0000000..aaec24f
--- /dev/null
+++ b/src/com/android/services/telephony/EmergencyTonePlayer.java
@@ -0,0 +1,133 @@
+/*
+ * 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.content.Context;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.ToneGenerator;
+import android.os.SystemVibrator;
+import android.os.Vibrator;
+import android.provider.Settings;
+
+/**
+ * Plays an emergency tone when placing emergency calls on CDMA devices.
+ */
+class EmergencyTonePlayer {
+
+    private static final int EMERGENCY_TONE_OFF = 0;
+    private static final int EMERGENCY_TONE_ALERT = 1;
+    private static final int EMERGENCY_TONE_VIBRATE = 2;
+
+    private static final int ALERT_RELATIVE_VOLUME_PERCENT = 100;
+
+    private static final int VIBRATE_LENGTH_MILLIS = 1000;
+    private static final int VIBRATE_PAUSE_MILLIS = 1000;
+    private static final long[] VIBRATE_PATTERN =
+            new long[] { VIBRATE_LENGTH_MILLIS, VIBRATE_PAUSE_MILLIS};
+
+    private static final AudioAttributes VIBRATION_ATTRIBUTES =
+            new AudioAttributes.Builder()
+                .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
+                .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
+                .build();
+
+    // We don't rely on getSystemService(Context.VIBRATOR_SERVICE) to make sure that this vibrator
+    // object will be isolated from others.
+    private final Vibrator mVibrator = new SystemVibrator();
+    private final Context mContext;
+    private final AudioManager mAudioManager;
+
+    private ToneGenerator mToneGenerator;
+    private int mSavedInCallVolume;
+    private boolean mIsVibrating = false;
+
+    EmergencyTonePlayer(Context context) {
+        mContext = context;
+        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+    }
+
+    public void start() {
+        switch (getToneSetting()) {
+            case EMERGENCY_TONE_VIBRATE:
+                startVibrate();
+                break;
+            case EMERGENCY_TONE_ALERT:
+                // Only start if we are not in silent mode.
+                int ringerMode = mAudioManager.getRingerMode();
+                if (ringerMode == AudioManager.RINGER_MODE_NORMAL) {
+                    startAlert();
+                }
+                break;
+            case EMERGENCY_TONE_OFF:
+                // nothing;
+                break;
+        }
+    }
+
+    public void stop() {
+        stopVibrate();
+        stopAlert();
+    }
+
+    private void startVibrate() {
+        if (!mIsVibrating) {
+            mVibrator.vibrate(VIBRATE_PATTERN, 0, VIBRATION_ATTRIBUTES);
+            mIsVibrating = true;
+        }
+    }
+
+    private void stopVibrate() {
+        if (mIsVibrating) {
+            mVibrator.cancel();
+            mIsVibrating = false;
+        }
+    }
+
+    private void startAlert() {
+        if (mToneGenerator == null) {
+            mToneGenerator = new ToneGenerator(
+                    AudioManager.STREAM_VOICE_CALL, ALERT_RELATIVE_VOLUME_PERCENT);
+
+            // Set the volume to max and save the old volume setting.
+            mSavedInCallVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
+            mAudioManager.setStreamVolume(
+                    AudioManager.STREAM_VOICE_CALL,
+                    mAudioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL),
+                    0);
+            mToneGenerator.startTone(ToneGenerator.TONE_CDMA_EMERGENCY_RINGBACK);
+        } else {
+            Log.d(this, "An alert is already running.");
+        }
+    }
+
+    private void stopAlert() {
+        if (mToneGenerator != null) {
+            mToneGenerator.stopTone();
+            mToneGenerator.release();
+            mToneGenerator = null;
+
+            mAudioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, mSavedInCallVolume, 0);
+            mSavedInCallVolume = 0;
+        }
+    }
+
+    private int getToneSetting() {
+       return Settings.Global.getInt(
+               mContext.getContentResolver(), Settings.Global.EMERGENCY_TONE, EMERGENCY_TONE_OFF);
+    }
+}
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 5935765..cb7894c 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -52,11 +52,13 @@
             new CdmaConferenceController(this);
     private ComponentName mExpectedComponentName = null;
     private EmergencyCallHelper mEmergencyCallHelper;
+    private EmergencyTonePlayer mEmergencyTonePlayer;
 
     @Override
     public void onCreate() {
         super.onCreate();
         mExpectedComponentName = new ComponentName(this, this.getClass());
+        mEmergencyTonePlayer = new EmergencyTonePlayer(this);
     }
 
     @Override
@@ -290,8 +292,8 @@
             return connection;
         } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
             boolean allowMute = allowMute(phone);
-            CdmaConnection connection =
-                    new CdmaConnection(originalConnection, allowMute, isOutgoing);
+            CdmaConnection connection = new CdmaConnection(
+                    originalConnection, mEmergencyTonePlayer, allowMute, isOutgoing);
             mCdmaConferenceController.add(connection);
             return connection;
         } else {