Merge "Attempt to unhold remaining holding call on disconnect (2/2)" into lmp-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index e779771..8cac409 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -436,13 +436,6 @@
             </intent-filter>
         </activity>
 
-        <!-- bluetooth phone service -->
-        <service android:name="BluetoothPhoneService">
-            <intent-filter>
-                <action android:name="android.bluetooth.IBluetoothHeadsetPhone" />
-            </intent-filter>
-        </service>
-
         <!-- Broadcast Receiver that will process BOOT Complete and launch OTA -->
         <receiver android:name="OtaStartupReceiver" android:exported="false"
                 androidprv:primaryUserOnly="true">
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 02eb9c8..82bd4f4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -125,6 +125,8 @@
     <!-- Label for the "Network settings" screen in the Settings UI -->
     <string name="settings_label">Network settings</string>
 
+    <!-- Label for settings screen for phone accounts. -->
+    <string name="phone_accounts">Phone account settings</string>
     <!-- Label for list item which opens a dialog to select the default outgoing account -->
     <string name="phone_accounts_make_calls_with">Make calls with</string>
     <!-- Label for list item which opens a dialog to select the default outgoing account for SIP calls. -->
@@ -149,6 +151,8 @@
     <string name="wifi_calling_do_not_use">Do not use Wi-Fi calling</string>
     <!-- Indication for option to not use a call assistant. -->
     <string name="wifi_calling_do_not_use_call_assistant">Do not use call assistant</string>
+    <!-- Indication for option to not use a call assistant. -->
+    <string name="wifi_calling_call_assistant_none">None</string>
     <!-- Label for selected Wi-Fi call manager -->
     <string name="wifi_calling_call_assistant">Call assistant</string>
     <!-- Label for switch setting to enable/disable the use of SIM call managers. -->
diff --git a/res/xml/phone_account_settings.xml b/res/xml/phone_account_settings.xml
index 7c34b93..f812885 100644
--- a/res/xml/phone_account_settings.xml
+++ b/res/xml/phone_account_settings.xml
@@ -32,7 +32,7 @@
         <com.android.phone.settings.AccountSelectionPreference
             android:key="wifi_calling_call_assistant_preference"
             android:title="@string/wifi_calling_call_assistant"
-            android:summary="@string/wifi_calling_call_assistant_configure_no_selection" />
+            android:summary="@string/wifi_calling_call_assistant_none" />
 
         <Preference
             android:key="wifi_calling_configure_call_assistant_preference"
@@ -46,6 +46,16 @@
         android:title="@string/sip_settings"
         android:persistent="false">
 
+        <PreferenceScreen
+            android:title="@string/sip_accounts"
+            android:persistent="false">
+
+            <intent android:action="android.intent.action.MAIN"
+                android:targetPackage="com.android.phone"
+                android:targetClass="com.android.services.telephony.sip.SipSettings" />
+
+        </PreferenceScreen>
+
         <ListPreference
             android:key="use_sip_calling_options_key"
             android:title="@string/sip_call_options_title"
@@ -53,6 +63,12 @@
             android:entries="@array/sip_call_options_entries"
             android:entryValues="@array/sip_call_options_values"/>
 
+        <CheckBoxPreference
+            android:key="sip_receive_calls_key"
+            android:title="@string/sip_receive_calls"
+            android:summary="@string/sip_receive_calls_summary"
+            android:persistent="true"/>
+
     </PreferenceCategory>
 
 </PreferenceScreen>
diff --git a/sip/res/xml/sip_setting.xml b/sip/res/xml/sip_setting.xml
index 91b8311..fa31e7c 100644
--- a/sip/res/xml/sip_setting.xml
+++ b/sip/res/xml/sip_setting.xml
@@ -16,12 +16,6 @@
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
     android:title="@string/sip_accounts">
 
-    <CheckBoxPreference
-        android:key="sip_receive_calls_key"
-        android:title="@string/sip_receive_calls"
-        android:summary="@string/sip_receive_calls_summary"
-        android:persistent="true"/>
-
     <PreferenceCategory android:key="sip_account_list" android:title="@string/sip_account_list"/>
 
 </PreferenceScreen>
diff --git a/sip/res/xml/sip_settings_category.xml b/sip/res/xml/sip_settings_category.xml
deleted file mode 100644
index 035a539..0000000
--- a/sip/res/xml/sip_settings_category.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 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.
--->
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:phone="http://schemas.android.com/apk/res/com.android.phone">
-
-    <PreferenceScreen
-        android:key="sip_settings_preference_screen_key"
-        android:title="@string/sip_settings"
-        android:persistent="false" >
-
-        <PreferenceScreen
-                android:key="sip_account_settings_key"
-                android:title="@string/sip_accounts_title"
-                android:persistent="false">
-
-            <intent android:action="android.intent.action.MAIN"
-                    android:targetPackage="com.android.phone"
-                    android:targetClass="com.android.services.telephony.sip.SipSettings" />
-
-        </PreferenceScreen>
-
-    </PreferenceScreen>
-
-</PreferenceScreen>
diff --git a/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java b/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java
index c808133..b54df59 100644
--- a/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java
+++ b/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java
@@ -33,7 +33,7 @@
 /**
  * Manages the {@link PhoneAccount} entries for SIP calling.
  */
-final class SipAccountRegistry {
+public final class SipAccountRegistry {
     private final class AccountEntry {
         private final SipProfile mProfile;
 
@@ -108,7 +108,7 @@
 
     private SipAccountRegistry() {}
 
-    static SipAccountRegistry getInstance() {
+    public static SipAccountRegistry getInstance() {
         return INSTANCE;
     }
 
@@ -172,7 +172,7 @@
      *
      * @param context The context.
      */
-    void restartSipService(Context context) {
+    public void restartSipService(Context context) {
         startSipProfiles(context, null);
     }
 
diff --git a/sip/src/com/android/services/telephony/sip/SipSettings.java b/sip/src/com/android/services/telephony/sip/SipSettings.java
index 525fd0f..7da0131 100644
--- a/sip/src/com/android/services/telephony/sip/SipSettings.java
+++ b/sip/src/com/android/services/telephony/sip/SipSettings.java
@@ -66,8 +66,6 @@
 
     static final String KEY_SIP_PROFILE = "sip_profile";
 
-    private static final String BUTTON_SIP_RECEIVE_CALLS =
-            "sip_receive_calls_key";
     private static final String PREF_SIP_LIST = "sip_account_list";
 
     private static final int REQUEST_ADD_OR_EDIT_SIP_PROFILE = 1;
@@ -78,7 +76,6 @@
 
     private SipProfile mProfile; // profile that's being edited
 
-    private CheckBoxPreference mButtonSipReceiveCalls;
     private PreferenceCategory mSipListContainer;
     private Map<String, SipPreference> mSipPreferenceMap;
     private List<SipProfile> mSipProfileList;
@@ -146,7 +143,6 @@
         setContentView(R.layout.sip_settings_ui);
         addPreferencesFromResource(R.xml.sip_setting);
         mSipListContainer = (PreferenceCategory) findPreference(PREF_SIP_LIST);
-        registerForReceiveCallsCheckBox();
 
         updateProfilesStatus();
 
@@ -159,8 +155,6 @@
     @Override
     public void onResume() {
         super.onResume();
-
-        mButtonSipReceiveCalls.setEnabled(SipUtil.isPhoneIdle(this));
     }
 
     @Override
@@ -195,62 +189,6 @@
         }.start();
     }
 
-    private void registerForReceiveCallsCheckBox() {
-        mButtonSipReceiveCalls = (CheckBoxPreference) findPreference
-                (BUTTON_SIP_RECEIVE_CALLS);
-        mButtonSipReceiveCalls.setChecked(
-                mSipSharedPreferences.isReceivingCallsEnabled());
-        mButtonSipReceiveCalls.setOnPreferenceClickListener(
-                new OnPreferenceClickListener() {
-                    public boolean onPreferenceClick(Preference preference) {
-                        final boolean enabled = ((CheckBoxPreference) preference).isChecked();
-                        new Thread(new Runnable() {
-                                public void run() {
-                                    handleSipReceiveCallsOption(enabled);
-                                }
-                        }).start();
-                        return true;
-                    }
-                });
-    }
-
-    /**
-     * Handles changes to the "receive calls" option.
-     *
-     * @param isReceivingCalls {@code True} if receiving incoming SIP calls.
-     */
-    private synchronized void handleSipReceiveCallsOption(boolean isReceivingCalls) {
-        mSipSharedPreferences.setReceivingCallsEnabled(isReceivingCalls);
-
-        // Mark all profiles as auto-register if we are now receiving calls.
-        List<SipProfile> sipProfileList = mProfileDb.retrieveSipProfileList();
-        for (SipProfile p : sipProfileList) {
-            p = updateAutoRegistrationFlag(p, isReceivingCalls);
-        }
-
-        // Restart all Sip services to ensure we reflect whether we are receiving calls.
-        SipAccountRegistry sipAccountRegistry = SipAccountRegistry.getInstance();
-        sipAccountRegistry.restartSipService(this);
-
-        updateProfilesStatus();
-    }
-
-    private SipProfile updateAutoRegistrationFlag(SipProfile p, boolean enabled) {
-        SipProfile newProfile = new SipProfile.Builder(p)
-                .setAutoRegistration(enabled)
-                .build();
-        try {
-            // Note: The profile is updated, but the associated PhoneAccount is left alone since
-            // the only thing that changed is the auto-registration flag, which is not part of the
-            // PhoneAccount.
-            mProfileDb.deleteProfile(p);
-            mProfileDb.saveProfile(newProfile);
-        } catch (Exception e) {
-            log("updateAutoRegistrationFlag, exception: " + e);
-        }
-        return newProfile;
-    }
-
     private void updateProfilesStatus() {
         new Thread(new Runnable() {
             @Override
@@ -494,6 +432,10 @@
                 startSipEditor(null);
                 return true;
             }
+            case android.R.id.home: {
+                onBackPressed();
+                return true;
+            }
         }
         return super.onOptionsItemSelected(item);
     }
diff --git a/sip/src/com/android/services/telephony/sip/SipUtil.java b/sip/src/com/android/services/telephony/sip/SipUtil.java
index e4d5d4c..f93f02d 100644
--- a/sip/src/com/android/services/telephony/sip/SipUtil.java
+++ b/sip/src/com/android/services/telephony/sip/SipUtil.java
@@ -30,8 +30,10 @@
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.text.TextUtils;
+import android.util.Log;
 
 import java.util.ArrayList;
+import java.util.List;
 
 public class SipUtil {
     static final String LOG_TAG = "SIP";
@@ -59,7 +61,7 @@
         return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
     }
 
-    static boolean isPhoneIdle(Context context) {
+    public static boolean isPhoneIdle(Context context) {
         TelecomManager manager = (TelecomManager) context.getSystemService(
                 Context.TELECOM_SERVICE);
         if (manager != null) {
@@ -131,4 +133,34 @@
         final SipSharedPreferences sipSharedPreferences = new SipSharedPreferences(context);
         return sipSharedPreferences.getSipCallOption().equals(Settings.System.SIP_ALWAYS);
     }
+
+    /**
+     * Updates SIP accounts to indicate whether they are enabled to receive incoming SIP calls.
+     *
+     * @param isEnabled {@code True} if receiving incoming SIP calls.
+     */
+    public static void useSipToReceiveIncomingCalls(Context context, boolean isEnabled) {
+        SipProfileDb profileDb = new SipProfileDb(context);
+
+        // Mark all profiles as auto-register if we are now receiving calls.
+        List<SipProfile> sipProfileList = profileDb.retrieveSipProfileList();
+        for (SipProfile p : sipProfileList) {
+            updateAutoRegistrationFlag(p, profileDb, isEnabled);
+        }
+    }
+
+    private static void updateAutoRegistrationFlag(
+            SipProfile p, SipProfileDb db, boolean isEnabled) {
+        SipProfile newProfile = new SipProfile.Builder(p).setAutoRegistration(isEnabled).build();
+
+        try {
+            // Note: The profile is updated, but the associated PhoneAccount is left alone since
+            // the only thing that changed is the auto-registration flag, which is not part of the
+            // PhoneAccount.
+            db.deleteProfile(p);
+            db.saveProfile(newProfile);
+        } catch (Exception e) {
+            Log.d(LOG_TAG, "updateAutoRegistrationFlag, exception: " + e);
+        }
+    }
 }
diff --git a/src/com/android/phone/BluetoothPhoneService.java b/src/com/android/phone/BluetoothPhoneService.java
deleted file mode 100644
index 653d671..0000000
--- a/src/com/android/phone/BluetoothPhoneService.java
+++ /dev/null
@@ -1,982 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.phone;
-
-import android.app.Service;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothProfile;
-import android.bluetooth.IBluetoothHeadsetPhone;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.AsyncResult;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.os.SystemProperties;
-import android.telephony.PhoneNumberUtils;
-import android.telephony.ServiceState;
-import android.util.Log;
-
-import com.android.internal.telephony.Call;
-import com.android.internal.telephony.Connection;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.CallManager;
-
-import com.android.phone.CallGatewayManager.RawGatewayInfo;
-
-import java.io.IOException;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Bluetooth headset manager for the Phone app.
- * @hide
- */
-public class BluetoothPhoneService extends Service {
-    private static final String TAG = "BluetoothPhoneService";
-    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 1)
-            && (SystemProperties.getInt("ro.debuggable", 0) == 1);
-    private static final boolean VDBG = (PhoneGlobals.DBG_LEVEL >= 2);  // even more logging
-
-    private static final String MODIFY_PHONE_STATE = android.Manifest.permission.MODIFY_PHONE_STATE;
-
-    private BluetoothAdapter mAdapter;
-    private CallManager mCM;
-    private CallGatewayManager mCallGatewayManager;
-
-    private BluetoothHeadset mBluetoothHeadset;
-
-    private PowerManager mPowerManager;
-
-    private WakeLock mStartCallWakeLock;  // held while waiting for the intent to start call
-
-    private PhoneConstants.State mPhoneState = PhoneConstants.State.IDLE;
-    CdmaPhoneCallState.PhoneCallState mCdmaThreeWayCallState =
-                                            CdmaPhoneCallState.PhoneCallState.IDLE;
-
-    private Call.State mForegroundCallState;
-    private Call.State mRingingCallState;
-    private CallNumber mRingNumber;
-    // number of active calls
-    int mNumActive;
-    // number of background (held) calls
-    int mNumHeld;
-
-    long mBgndEarliestConnectionTime = 0;
-
-    // CDMA specific flag used in context with BT devices having display capabilities
-    // to show which Caller is active. This state might not be always true as in CDMA
-    // networks if a caller drops off no update is provided to the Phone.
-    // This flag is just used as a toggle to provide a update to the BT device to specify
-    // which caller is active.
-    private boolean mCdmaIsSecondCallActive = false;
-    private boolean mCdmaCallsSwapped = false;
-
-    private long[] mClccTimestamps; // Timestamps associated with each clcc index
-    private boolean[] mClccUsed;     // Is this clcc index in use
-
-    private static final int GSM_MAX_CONNECTIONS = 6;  // Max connections allowed by GSM
-    private static final int CDMA_MAX_CONNECTIONS = 2;  // Max connections allowed by CDMA
-    private IntentFilter mIntentFilter;
-
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
-            if (VDBG) Log.d(TAG, "Received BLUETOOTH_STATE_CHANGED_ACTION state:" + state);
-            if(state == BluetoothAdapter.STATE_ON) {
-                if (DBG) Log.d(TAG, "Bluetooth Turned ON, query phone state");
-                Message msg = Message.obtain(mHandler, QUERY_PHONE_STATE);
-                mHandler.sendMessage(msg);
-            }
-        }
-    };
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        mCM = CallManager.getInstance();
-        mAdapter = BluetoothAdapter.getDefaultAdapter();
-        if (mAdapter == null) {
-            if (VDBG) Log.d(TAG, "mAdapter null");
-            return;
-        }
-        mCallGatewayManager = CallGatewayManager.getInstance();
-
-        mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
-        mStartCallWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
-                                                       TAG + ":StartCall");
-        mStartCallWakeLock.setReferenceCounted(false);
-
-        mAdapter.getProfileProxy(this, mProfileListener, BluetoothProfile.HEADSET);
-
-        mForegroundCallState = Call.State.IDLE;
-        mRingingCallState = Call.State.IDLE;
-        mNumActive = 0;
-        mNumHeld = 0;
-        mRingNumber = new CallNumber("", 0);;
-
-        handlePreciseCallStateChange(null);
-
-        if(VDBG) Log.d(TAG, "onCreate register for updates");
-        // register for updates
-        mCM.registerForPreciseCallStateChanged(mHandler, PRECISE_CALL_STATE_CHANGED, null);
-        mCM.registerForCallWaiting(mHandler, PHONE_CDMA_CALL_WAITING, null);
-        mCM.registerForDisconnect(mHandler, PHONE_ON_DISCONNECT, null);
-
-        mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
-        this.registerReceiver(mReceiver, mIntentFilter);
-        // TODO(BT) registerForIncomingRing?
-        mClccTimestamps = new long[GSM_MAX_CONNECTIONS];
-        mClccUsed = new boolean[GSM_MAX_CONNECTIONS];
-        for (int i = 0; i < GSM_MAX_CONNECTIONS; i++) {
-            mClccUsed[i] = false;
-        }
-    }
-
-    @Override
-    public void onStart(Intent intent, int startId) {
-        if (mAdapter == null) {
-            Log.w(TAG, "Stopping Bluetooth BluetoothPhoneService Service: device does not have BT");
-            stopSelf();
-        }
-        if (VDBG) Log.d(TAG, "BluetoothPhoneService started");
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        if (DBG) log("Stopping Bluetooth BluetoothPhoneService Service");
-        this.unregisterReceiver(mReceiver);
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return mBinder;
-    }
-
-    private static final int PRECISE_CALL_STATE_CHANGED = 1;
-    private static final int PHONE_CDMA_CALL_WAITING = 2;
-    private static final int LIST_CURRENT_CALLS = 3;
-    private static final int QUERY_PHONE_STATE = 4;
-    private static final int CDMA_SWAP_SECOND_CALL_STATE = 5;
-    private static final int CDMA_SET_SECOND_CALL_STATE = 6;
-    private static final int PHONE_ON_DISCONNECT = 7;
-
-    private Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            if (VDBG) Log.d(TAG, "handleMessage: " + msg.what);
-            switch(msg.what) {
-                case PRECISE_CALL_STATE_CHANGED:
-                case PHONE_CDMA_CALL_WAITING:
-                case PHONE_ON_DISCONNECT:
-                    Connection connection = null;
-                    if (((AsyncResult) msg.obj).result instanceof Connection) {
-                        connection = (Connection) ((AsyncResult) msg.obj).result;
-                    }
-                    handlePreciseCallStateChange(connection);
-                    break;
-                case LIST_CURRENT_CALLS:
-                    handleListCurrentCalls();
-                    break;
-                case QUERY_PHONE_STATE:
-                    handleQueryPhoneState();
-                    break;
-                case CDMA_SWAP_SECOND_CALL_STATE:
-                    handleCdmaSwapSecondCallState();
-                    break;
-                case CDMA_SET_SECOND_CALL_STATE:
-                    handleCdmaSetSecondCallState((Boolean) msg.obj);
-                    break;
-            }
-        }
-    };
-
-    private void updateBtPhoneStateAfterRadioTechnologyChange() {
-        if(VDBG) Log.d(TAG, "updateBtPhoneStateAfterRadioTechnologyChange...");
-
-        //Unregister all events from the old obsolete phone
-        mCM.unregisterForPreciseCallStateChanged(mHandler);
-        mCM.unregisterForCallWaiting(mHandler);
-
-        //Register all events new to the new active phone
-        mCM.registerForPreciseCallStateChanged(mHandler,
-                                               PRECISE_CALL_STATE_CHANGED, null);
-        mCM.registerForCallWaiting(mHandler,
-                                   PHONE_CDMA_CALL_WAITING, null);
-    }
-
-    private void handlePreciseCallStateChange(Connection connection) {
-        // get foreground call state
-        int oldNumActive = mNumActive;
-        int oldNumHeld = mNumHeld;
-        Call.State oldRingingCallState = mRingingCallState;
-        Call.State oldForegroundCallState = mForegroundCallState;
-        CallNumber oldRingNumber = mRingNumber;
-
-        Call foregroundCall = mCM.getActiveFgCall();
-
-        if (VDBG)
-            Log.d(TAG, " handlePreciseCallStateChange: foreground: " + foregroundCall +
-                " background: " + mCM.getFirstActiveBgCall() + " ringing: " +
-                mCM.getFirstActiveRingingCall());
-
-        mForegroundCallState = foregroundCall.getState();
-        /* if in transition, do not update */
-        if (mForegroundCallState == Call.State.DISCONNECTING)
-        {
-            Log.d(TAG, "handlePreciseCallStateChange. Call disconnecting, wait before update");
-            return;
-        }
-        else
-            mNumActive = (mForegroundCallState == Call.State.ACTIVE) ? 1 : 0;
-
-        Call ringingCall = mCM.getFirstActiveRingingCall();
-        mRingingCallState = ringingCall.getState();
-        mRingNumber = getCallNumber(connection, ringingCall);
-
-        if (mCM.getDefaultPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
-            mNumHeld = getNumHeldCdma();
-            PhoneGlobals app = PhoneGlobals.getInstance();
-            if (app.cdmaPhoneCallState != null) {
-                CdmaPhoneCallState.PhoneCallState currCdmaThreeWayCallState =
-                        app.cdmaPhoneCallState.getCurrentCallState();
-                CdmaPhoneCallState.PhoneCallState prevCdmaThreeWayCallState =
-                    app.cdmaPhoneCallState.getPreviousCallState();
-
-                log("CDMA call state: " + currCdmaThreeWayCallState + " prev state:" +
-                    prevCdmaThreeWayCallState);
-
-                if ((mBluetoothHeadset != null) &&
-                    (mCdmaThreeWayCallState != currCdmaThreeWayCallState)) {
-                    // In CDMA, the network does not provide any feedback
-                    // to the phone when the 2nd MO call goes through the
-                    // stages of DIALING > ALERTING -> ACTIVE we fake the
-                    // sequence
-                    log("CDMA 3way call state change. mNumActive: " + mNumActive +
-                        " mNumHeld: " + mNumHeld + " IsThreeWayCallOrigStateDialing: " +
-                        app.cdmaPhoneCallState.IsThreeWayCallOrigStateDialing());
-                    if ((currCdmaThreeWayCallState ==
-                            CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE)
-                                && app.cdmaPhoneCallState.IsThreeWayCallOrigStateDialing()) {
-                        // Mimic dialing, put the call on hold, alerting
-                        mBluetoothHeadset.phoneStateChanged(0, mNumHeld,
-                            convertCallState(Call.State.IDLE, Call.State.DIALING),
-                            mRingNumber.mNumber, mRingNumber.mType);
-
-                        mBluetoothHeadset.phoneStateChanged(0, mNumHeld,
-                            convertCallState(Call.State.IDLE, Call.State.ALERTING),
-                            mRingNumber.mNumber, mRingNumber.mType);
-
-                    }
-
-                    // In CDMA, the network does not provide any feedback to
-                    // the phone when a user merges a 3way call or swaps
-                    // between two calls we need to send a CIEV response
-                    // indicating that a call state got changed which should
-                    // trigger a CLCC update request from the BT client.
-                    if (currCdmaThreeWayCallState ==
-                            CdmaPhoneCallState.PhoneCallState.CONF_CALL &&
-                            prevCdmaThreeWayCallState ==
-                              CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
-                        log("CDMA 3way conf call. mNumActive: " + mNumActive +
-                            " mNumHeld: " + mNumHeld);
-                        mBluetoothHeadset.phoneStateChanged(mNumActive, mNumHeld,
-                            convertCallState(Call.State.IDLE, mForegroundCallState),
-                            mRingNumber.mNumber, mRingNumber.mType);
-                    }
-                }
-                mCdmaThreeWayCallState = currCdmaThreeWayCallState;
-            }
-        } else {
-            mNumHeld = getNumHeldUmts();
-        }
-
-        boolean callsSwitched = false;
-        if (mCM.getDefaultPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA &&
-            mCdmaThreeWayCallState == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
-            callsSwitched = mCdmaCallsSwapped;
-        } else {
-            Call backgroundCall = mCM.getFirstActiveBgCall();
-            callsSwitched =
-                (mNumHeld == 1 && ! (backgroundCall.getEarliestConnectTime() ==
-                    mBgndEarliestConnectionTime));
-            mBgndEarliestConnectionTime = backgroundCall.getEarliestConnectTime();
-        }
-
-        if (mNumActive != oldNumActive || mNumHeld != oldNumHeld ||
-            mRingingCallState != oldRingingCallState ||
-            mForegroundCallState != oldForegroundCallState ||
-            !mRingNumber.equalTo(oldRingNumber) ||
-            callsSwitched) {
-            if (mBluetoothHeadset != null) {
-                mBluetoothHeadset.phoneStateChanged(mNumActive, mNumHeld,
-                    convertCallState(mRingingCallState, mForegroundCallState),
-                    mRingNumber.mNumber, mRingNumber.mType);
-            }
-        }
-    }
-
-    private void handleListCurrentCalls() {
-        Phone phone = mCM.getDefaultPhone();
-        int phoneType = phone.getPhoneType();
-
-        // TODO(BT) handle virtual call
-
-        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
-            listCurrentCallsCdma();
-        } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
-            listCurrentCallsGsm();
-        } else {
-            Log.e(TAG, "Unexpected phone type: " + phoneType);
-        }
-        // end the result
-        // when index is 0, other parameter does not matter
-        if (mBluetoothHeadset != null) {
-            mBluetoothHeadset.clccResponse(0, 0, 0, 0, false, "", 0);
-        }
-    }
-
-    private void handleQueryPhoneState() {
-        if (mBluetoothHeadset != null) {
-            mBluetoothHeadset.phoneStateChanged(mNumActive, mNumHeld,
-                convertCallState(mRingingCallState, mForegroundCallState),
-                mRingNumber.mNumber, mRingNumber.mType);
-        }
-    }
-
-    private int getNumHeldUmts() {
-        int countHeld = 0;
-        List<Call> heldCalls = mCM.getBackgroundCalls();
-
-        for (Call call : heldCalls) {
-            if (call.getState() == Call.State.HOLDING) {
-                countHeld++;
-            }
-        }
-        return countHeld;
-    }
-
-    private int getNumHeldCdma() {
-        int numHeld = 0;
-        PhoneGlobals app = PhoneGlobals.getInstance();
-        if (app.cdmaPhoneCallState != null) {
-            CdmaPhoneCallState.PhoneCallState curr3WayCallState =
-                app.cdmaPhoneCallState.getCurrentCallState();
-            CdmaPhoneCallState.PhoneCallState prev3WayCallState =
-                app.cdmaPhoneCallState.getPreviousCallState();
-
-            log("CDMA call state: " + curr3WayCallState + " prev state:" +
-                prev3WayCallState);
-            if (curr3WayCallState == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
-                if (prev3WayCallState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
-                    numHeld = 0; //0: no calls held, as now *both* the caller are active
-                } else {
-                    numHeld = 1; //1: held call and active call, as on answering a
-                    // Call Waiting, one of the caller *is* put on hold
-                }
-            } else if (curr3WayCallState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
-                numHeld = 1; //1: held call and active call, as on make a 3 Way Call
-                // the first caller *is* put on hold
-            } else {
-                numHeld = 0; //0: no calls held as this is a SINGLE_ACTIVE call
-            }
-        }
-        return numHeld;
-    }
-
-    private CallNumber getCallNumber(Connection connection, Call call) {
-        String number = null;
-        int type = 128;
-        // find phone number and type
-        if (connection == null) {
-            connection = call.getEarliestConnection();
-            if (connection == null) {
-                Log.e(TAG, "Could not get a handle on Connection object for the call");
-            }
-        }
-        if (connection != null) {
-            number = connection.getAddress();
-            if (number != null) {
-                type = PhoneNumberUtils.toaFromString(number);
-            }
-        }
-        if (number == null) {
-            number = "";
-        }
-        return new CallNumber(number, type);
-    }
-
-    private class CallNumber
-    {
-        private String mNumber = null;
-        private int mType = 0;
-
-        private CallNumber(String number, int type) {
-            mNumber = number;
-            mType = type;
-        }
-
-        private boolean equalTo(CallNumber callNumber)
-        {
-            if (mType != callNumber.mType) return false;
-
-            if (mNumber != null && mNumber.compareTo(callNumber.mNumber) == 0) {
-                return true;
-            }
-            return false;
-        }
-    }
-
-    private BluetoothProfile.ServiceListener mProfileListener =
-            new BluetoothProfile.ServiceListener() {
-        public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            mBluetoothHeadset = (BluetoothHeadset) proxy;
-        }
-        public void onServiceDisconnected(int profile) {
-            mBluetoothHeadset = null;
-        }
-    };
-
-    private void listCurrentCallsGsm() {
-        // Collect all known connections
-        // clccConnections isindexed by CLCC index
-        Connection[] clccConnections = new Connection[GSM_MAX_CONNECTIONS];
-        LinkedList<Connection> newConnections = new LinkedList<Connection>();
-        LinkedList<Connection> connections = new LinkedList<Connection>();
-
-        Call foregroundCall = mCM.getActiveFgCall();
-        Call backgroundCall = mCM.getFirstActiveBgCall();
-        Call ringingCall = mCM.getFirstActiveRingingCall();
-
-        if (ringingCall.getState().isAlive()) {
-            connections.addAll(ringingCall.getConnections());
-        }
-        if (foregroundCall.getState().isAlive()) {
-            connections.addAll(foregroundCall.getConnections());
-        }
-        if (backgroundCall.getState().isAlive()) {
-            connections.addAll(backgroundCall.getConnections());
-        }
-
-        // Mark connections that we already known about
-        boolean clccUsed[] = new boolean[GSM_MAX_CONNECTIONS];
-        for (int i = 0; i < GSM_MAX_CONNECTIONS; i++) {
-            clccUsed[i] = mClccUsed[i];
-            mClccUsed[i] = false;
-        }
-        for (Connection c : connections) {
-            boolean found = false;
-            long timestamp = c.getCreateTime();
-            for (int i = 0; i < GSM_MAX_CONNECTIONS; i++) {
-                if (clccUsed[i] && timestamp == mClccTimestamps[i]) {
-                    mClccUsed[i] = true;
-                    found = true;
-                    clccConnections[i] = c;
-                    break;
-                }
-            }
-            if (!found) {
-                newConnections.add(c);
-            }
-        }
-
-        // Find a CLCC index for new connections
-        while (!newConnections.isEmpty()) {
-            // Find lowest empty index
-            int i = 0;
-            while (mClccUsed[i]) i++;
-            // Find earliest connection
-            long earliestTimestamp = newConnections.get(0).getCreateTime();
-            Connection earliestConnection = newConnections.get(0);
-            for (int j = 0; j < newConnections.size(); j++) {
-                long timestamp = newConnections.get(j).getCreateTime();
-                if (timestamp < earliestTimestamp) {
-                    earliestTimestamp = timestamp;
-                    earliestConnection = newConnections.get(j);
-                }
-            }
-
-            // update
-            mClccUsed[i] = true;
-            mClccTimestamps[i] = earliestTimestamp;
-            clccConnections[i] = earliestConnection;
-            newConnections.remove(earliestConnection);
-        }
-
-        // Send CLCC response to Bluetooth headset service
-        for (int i = 0; i < clccConnections.length; i++) {
-            if (mClccUsed[i]) {
-                sendClccResponseGsm(i, clccConnections[i]);
-            }
-        }
-    }
-
-    /** Convert a Connection object into a single +CLCC result */
-    private void sendClccResponseGsm(int index, Connection connection) {
-        int state = convertCallState(connection.getState());
-        boolean mpty = false;
-        Call call = connection.getCall();
-        if (call != null) {
-            mpty = call.isMultiparty();
-        }
-
-        boolean isIncoming = connection.isIncoming();
-
-        // For GV outgoing calls send the contact phone #, not the gateway #.
-        String number = connection.getAddress();
-        if (!isIncoming) {
-            RawGatewayInfo rawInfo = mCallGatewayManager.getGatewayInfo(connection);
-            if (!rawInfo.isEmpty()) {
-                number = rawInfo.trueNumber;
-            }
-        }
-        int type = -1;
-        if (number != null) {
-            type = PhoneNumberUtils.toaFromString(number);
-        } else {
-            number = "";
-        }
-
-        if (mBluetoothHeadset != null) {
-            mBluetoothHeadset.clccResponse(index + 1, isIncoming ? 1 : 0,
-                    state, 0, mpty, number, type);
-        }
-    }
-
-    /** Build the +CLCC result for CDMA
-     *  The complexity arises from the fact that we need to maintain the same
-     *  CLCC index even as a call moves between states. */
-    private synchronized void listCurrentCallsCdma() {
-        // In CDMA at one time a user can have only two live/active connections
-        Connection[] clccConnections = new Connection[CDMA_MAX_CONNECTIONS];// indexed by CLCC index
-        Call foregroundCall = mCM.getActiveFgCall();
-        Call ringingCall = mCM.getFirstActiveRingingCall();
-
-        Call.State ringingCallState = ringingCall.getState();
-        // If the Ringing Call state is INCOMING, that means this is the very first call
-        // hence there should not be any Foreground Call
-        if (ringingCallState == Call.State.INCOMING) {
-            if (VDBG) log("Filling clccConnections[0] for INCOMING state");
-            clccConnections[0] = ringingCall.getLatestConnection();
-        } else if (foregroundCall.getState().isAlive()) {
-            // Getting Foreground Call connection based on Call state
-            if (ringingCall.isRinging()) {
-                if (VDBG) log("Filling clccConnections[0] & [1] for CALL WAITING state");
-                clccConnections[0] = foregroundCall.getEarliestConnection();
-                clccConnections[1] = ringingCall.getLatestConnection();
-            } else {
-                if (foregroundCall.getConnections().size() <= 1) {
-                    // Single call scenario
-                    if (VDBG) {
-                        log("Filling clccConnections[0] with ForgroundCall latest connection");
-                    }
-                    clccConnections[0] = foregroundCall.getLatestConnection();
-                } else {
-                    // Multiple Call scenario. This would be true for both
-                    // CONF_CALL and THRWAY_ACTIVE state
-                    if (VDBG) {
-                        log("Filling clccConnections[0] & [1] with ForgroundCall connections");
-                    }
-                    clccConnections[0] = foregroundCall.getEarliestConnection();
-                    clccConnections[1] = foregroundCall.getLatestConnection();
-                }
-            }
-        }
-
-        // Update the mCdmaIsSecondCallActive flag based on the Phone call state
-        if (PhoneGlobals.getInstance().cdmaPhoneCallState.getCurrentCallState()
-                == CdmaPhoneCallState.PhoneCallState.SINGLE_ACTIVE) {
-            Message msg = mHandler.obtainMessage(CDMA_SET_SECOND_CALL_STATE, false);
-            mHandler.sendMessage(msg);
-        } else if (PhoneGlobals.getInstance().cdmaPhoneCallState.getCurrentCallState()
-                == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
-            Message msg = mHandler.obtainMessage(CDMA_SET_SECOND_CALL_STATE, true);
-            mHandler.sendMessage(msg);
-        }
-
-        // send CLCC result
-        for (int i = 0; (i < clccConnections.length) && (clccConnections[i] != null); i++) {
-            sendClccResponseCdma(i, clccConnections[i]);
-        }
-    }
-
-    /** Send ClCC results for a Connection object for CDMA phone */
-    private void sendClccResponseCdma(int index, Connection connection) {
-        int state;
-        PhoneGlobals app = PhoneGlobals.getInstance();
-        CdmaPhoneCallState.PhoneCallState currCdmaCallState =
-                app.cdmaPhoneCallState.getCurrentCallState();
-        CdmaPhoneCallState.PhoneCallState prevCdmaCallState =
-                app.cdmaPhoneCallState.getPreviousCallState();
-
-        if ((prevCdmaCallState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE)
-                && (currCdmaCallState == CdmaPhoneCallState.PhoneCallState.CONF_CALL)) {
-            // If the current state is reached after merging two calls
-            // we set the state of all the connections as ACTIVE
-            state = CALL_STATE_ACTIVE;
-        } else {
-            Call.State callState = connection.getState();
-            switch (callState) {
-            case ACTIVE:
-                // For CDMA since both the connections are set as active by FW after accepting
-                // a Call waiting or making a 3 way call, we need to set the state specifically
-                // to ACTIVE/HOLDING based on the mCdmaIsSecondCallActive flag. This way the
-                // CLCC result will allow BT devices to enable the swap or merge options
-                if (index == 0) { // For the 1st active connection
-                    state = mCdmaIsSecondCallActive ? CALL_STATE_HELD : CALL_STATE_ACTIVE;
-                } else { // for the 2nd active connection
-                    state = mCdmaIsSecondCallActive ? CALL_STATE_ACTIVE : CALL_STATE_HELD;
-                }
-                break;
-            case HOLDING:
-                state = CALL_STATE_HELD;
-                break;
-            case DIALING:
-                state = CALL_STATE_DIALING;
-                break;
-            case ALERTING:
-                state = CALL_STATE_ALERTING;
-                break;
-            case INCOMING:
-                state = CALL_STATE_INCOMING;
-                break;
-            case WAITING:
-                state = CALL_STATE_WAITING;
-                break;
-            default:
-                Log.e(TAG, "bad call state: " + callState);
-                return;
-            }
-        }
-
-        boolean mpty = false;
-        if (currCdmaCallState == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
-            if (prevCdmaCallState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
-                // If the current state is reached after merging two calls
-                // we set the multiparty call true.
-                mpty = true;
-            } // else
-                // CALL_CONF state is not from merging two calls, but from
-                // accepting the second call. In this case first will be on
-                // hold in most cases but in some cases its already merged.
-                // However, we will follow the common case and the test case
-                // as per Bluetooth SIG PTS
-        }
-
-        boolean isIncoming = connection.isIncoming();
-
-        // For GV outgoing calls send the contact phone #, not the gateway #.
-        String number = connection.getAddress();
-        if (!isIncoming) {
-            RawGatewayInfo rawInfo = mCallGatewayManager.getGatewayInfo(connection);
-            if (!rawInfo.isEmpty()) {
-                number = rawInfo.trueNumber;
-            }
-        }
-        int type = -1;
-        if (number != null) {
-            type = PhoneNumberUtils.toaFromString(number);
-        } else {
-            number = "";
-        }
-
-        if (mBluetoothHeadset != null) {
-            mBluetoothHeadset.clccResponse(index + 1, isIncoming ? 1 : 0,
-                    state, 0, mpty, number, type);
-        }
-    }
-
-    private void handleCdmaSwapSecondCallState() {
-        if (VDBG) log("cdmaSwapSecondCallState: Toggling mCdmaIsSecondCallActive");
-        mCdmaIsSecondCallActive = !mCdmaIsSecondCallActive;
-        mCdmaCallsSwapped = true;
-    }
-
-    private void handleCdmaSetSecondCallState(boolean state) {
-        if (VDBG) log("cdmaSetSecondCallState: Setting mCdmaIsSecondCallActive to " + state);
-        mCdmaIsSecondCallActive = state;
-
-        if (!mCdmaIsSecondCallActive) {
-            mCdmaCallsSwapped = false;
-        }
-    }
-
-    private final IBluetoothHeadsetPhone.Stub mBinder = new IBluetoothHeadsetPhone.Stub() {
-        public boolean answerCall() {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
-            return PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
-        }
-
-        public boolean hangupCall() {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
-            if (mCM.hasActiveFgCall()) {
-                return PhoneUtils.hangupActiveCall(mCM.getActiveFgCall());
-            } else if (mCM.hasActiveRingingCall()) {
-                return PhoneUtils.hangupRingingCall(mCM.getFirstActiveRingingCall());
-            } else if (mCM.hasActiveBgCall()) {
-                return PhoneUtils.hangupHoldingCall(mCM.getFirstActiveBgCall());
-            }
-            // TODO(BT) handle virtual voice call
-            return false;
-        }
-
-        public boolean sendDtmf(int dtmf) {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
-            return mCM.sendDtmf((char) dtmf);
-        }
-
-        public boolean processChld(int chld) {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
-            Phone phone = mCM.getDefaultPhone();
-            int phoneType = phone.getPhoneType();
-            Call ringingCall = mCM.getFirstActiveRingingCall();
-            Call backgroundCall = mCM.getFirstActiveBgCall();
-
-            if (chld == CHLD_TYPE_RELEASEHELD) {
-                if (ringingCall.isRinging()) {
-                    return PhoneUtils.hangupRingingCall(ringingCall);
-                } else {
-                    return PhoneUtils.hangupHoldingCall(backgroundCall);
-                }
-            } else if (chld == CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD) {
-                if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
-                    if (ringingCall.isRinging()) {
-                        // Hangup the active call and then answer call waiting call.
-                        if (VDBG) log("CHLD:1 Callwaiting Answer call");
-                        PhoneUtils.hangupRingingAndActive(phone);
-                    } else {
-                        // If there is no Call waiting then just hangup
-                        // the active call. In CDMA this mean that the complete
-                        // call session would be ended
-                        if (VDBG) log("CHLD:1 Hangup Call");
-                        PhoneUtils.hangup(PhoneGlobals.getInstance().mCM);
-                    }
-                    return true;
-                } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
-                    if (ringingCall.isRinging() && (mNumHeld > 0 && mNumActive == 0)) {
-                       if (VDBG) log("CHLD:1 Answer the Call");
-                       return PhoneUtils.answerCall(ringingCall);
-                    }
-                    // Hangup active call, answer held call
-                    return PhoneUtils.answerAndEndActive(PhoneGlobals.getInstance().mCM, ringingCall);
-                } else {
-                    Log.e(TAG, "bad phone type: " + phoneType);
-                    return false;
-                }
-            } else if (chld == CHLD_TYPE_HOLDACTIVE_ACCEPTHELD) {
-                if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
-                    // For CDMA, the way we switch to a new incoming call is by
-                    // calling PhoneUtils.answerCall(). switchAndHoldActive() won't
-                    // properly update the call state within telephony.
-                    // If the Phone state is already in CONF_CALL then we simply send
-                    // a flash cmd by calling switchHoldingAndActive()
-                    if (ringingCall.isRinging()) {
-                        if (VDBG) log("CHLD:2 Callwaiting Answer call");
-                        PhoneUtils.answerCall(ringingCall);
-                        // Setting the second callers state flag to TRUE (i.e. active)
-                        cdmaSetSecondCallState(true);
-                        return true;
-                    } else if (PhoneGlobals.getInstance().cdmaPhoneCallState
-                               .getCurrentCallState()
-                               == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
-                        if (VDBG) log("CHLD:2 Swap Calls");
-                        PhoneUtils.switchHoldingAndActive(backgroundCall);
-                        // Toggle the second callers active state flag
-                        cdmaSwapSecondCallState();
-                        return true;
-                    }
-                    Log.e(TAG, "CDMA fail to do hold active and accept held");
-                    return false;
-                } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
-                    if (ringingCall.isRinging() && (mNumHeld > 0 && mNumActive == 0)) {
-                       PhoneUtils.answerCall(ringingCall);
-                    } else {
-                       PhoneUtils.switchHoldingAndActive(backgroundCall);
-                    }
-                    return true;
-                } else {
-                    Log.e(TAG, "Unexpected phone type: " + phoneType);
-                    return false;
-                }
-            } else if (chld == CHLD_TYPE_ADDHELDTOCONF) {
-                if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
-                    CdmaPhoneCallState.PhoneCallState state =
-                        PhoneGlobals.getInstance().cdmaPhoneCallState.getCurrentCallState();
-                    // For CDMA, we need to check if the call is in THRWAY_ACTIVE state
-                    if (state == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
-                        if (VDBG) log("CHLD:3 Merge Calls");
-                        PhoneUtils.mergeCalls();
-                        return true;
-                    }   else if (state == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
-                        // State is CONF_CALL already and we are getting a merge call
-                        // This can happen when CONF_CALL was entered from a Call Waiting
-                        // TODO(BT)
-                        return false;
-                    }
-                    Log.e(TAG, "GSG no call to add conference");
-                    return false;
-                } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
-                    if (mCM.hasActiveFgCall() && mCM.hasActiveBgCall()) {
-                        PhoneUtils.mergeCalls();
-                        return true;
-                    } else {
-                        Log.e(TAG, "GSG no call to merge");
-                        return false;
-                    }
-                } else {
-                    Log.e(TAG, "Unexpected phone type: " + phoneType);
-                    return false;
-                }
-            } else {
-                Log.e(TAG, "bad CHLD value: " + chld);
-                return false;
-            }
-        }
-
-        public String getNetworkOperator() {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
-            return mCM.getDefaultPhone().getServiceState().getOperatorAlphaLong();
-        }
-
-        public String getSubscriberNumber() {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
-            return mCM.getDefaultPhone().getLine1Number();
-        }
-
-        public boolean listCurrentCalls() {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
-            Message msg = Message.obtain(mHandler, LIST_CURRENT_CALLS);
-            mHandler.sendMessage(msg);
-            return true;
-        }
-
-        public boolean queryPhoneState() {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
-            Message msg = Message.obtain(mHandler, QUERY_PHONE_STATE);
-            mHandler.sendMessage(msg);
-            return true;
-        }
-
-        public void updateBtHandsfreeAfterRadioTechnologyChange() {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
-            if (VDBG) Log.d(TAG, "updateBtHandsfreeAfterRadioTechnologyChange...");
-            updateBtPhoneStateAfterRadioTechnologyChange();
-        }
-
-        public void cdmaSwapSecondCallState() {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
-            Message msg = Message.obtain(mHandler, CDMA_SWAP_SECOND_CALL_STATE);
-            mHandler.sendMessage(msg);
-        }
-
-        public void cdmaSetSecondCallState(boolean state) {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
-            Message msg = mHandler.obtainMessage(CDMA_SET_SECOND_CALL_STATE, state);
-            mHandler.sendMessage(msg);
-        }
-    };
-
-    // match up with bthf_call_state_t of bt_hf.h
-    final static int CALL_STATE_ACTIVE = 0;
-    final static int CALL_STATE_HELD = 1;
-    final static int CALL_STATE_DIALING = 2;
-    final static int CALL_STATE_ALERTING = 3;
-    final static int CALL_STATE_INCOMING = 4;
-    final static int CALL_STATE_WAITING = 5;
-    final static int CALL_STATE_IDLE = 6;
-
-    // match up with bthf_chld_type_t of bt_hf.h
-    final static int CHLD_TYPE_RELEASEHELD = 0;
-    final static int CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD = 1;
-    final static int CHLD_TYPE_HOLDACTIVE_ACCEPTHELD = 2;
-    final static int CHLD_TYPE_ADDHELDTOCONF = 3;
-
-     /* Convert telephony phone call state into hf hal call state */
-    static int convertCallState(Call.State ringingState, Call.State foregroundState) {
-        int retval = CALL_STATE_IDLE;
-
-        if ((ringingState == Call.State.INCOMING) ||
-            (ringingState == Call.State.WAITING) )
-            retval = CALL_STATE_INCOMING;
-        else if (foregroundState == Call.State.DIALING)
-            retval = CALL_STATE_DIALING;
-        else if (foregroundState == Call.State.ALERTING)
-            retval = CALL_STATE_ALERTING;
-        else
-            retval = CALL_STATE_IDLE;
-
-        if (VDBG) {
-            Log.v(TAG, "Call state Converted2: " + ringingState + "/" + foregroundState + " -> " +
-                    retval);
-        }
-        return retval;
-    }
-
-    static int convertCallState(Call.State callState) {
-        int retval = CALL_STATE_IDLE;
-
-        switch (callState) {
-        case IDLE:
-        case DISCONNECTED:
-        case DISCONNECTING:
-            retval = CALL_STATE_IDLE;
-            break;
-        case ACTIVE:
-            retval = CALL_STATE_ACTIVE;
-            break;
-        case HOLDING:
-            retval = CALL_STATE_HELD;
-            break;
-        case DIALING:
-            retval = CALL_STATE_DIALING;
-            break;
-        case ALERTING:
-            retval = CALL_STATE_ALERTING;
-            break;
-        case INCOMING:
-            retval = CALL_STATE_INCOMING;
-            break;
-        case WAITING:
-            retval = CALL_STATE_WAITING;
-            break;
-        default:
-            Log.e(TAG, "bad call state: " + callState);
-            retval = CALL_STATE_IDLE;
-            break;
-        }
-
-        if (VDBG) {
-            Log.v(TAG, "Call state Converted2: " + callState + " -> " + retval);
-        }
-
-        return retval;
-    }
-
-    private static void log(String msg) {
-        Log.d(TAG, msg);
-    }
-}
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index d1bb25a..b85cb7e 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -155,6 +155,7 @@
 
     // String keys for preference lookup
     // TODO: Naming these "BUTTON_*" is confusing since they're not actually buttons(!)
+    private static final String VOICEMAIL_SETTING_SCREEN_PREF_KEY = "button_voicemail_category_key";
     private static final String BUTTON_VOICEMAIL_KEY = "button_voicemail_key";
     private static final String BUTTON_VOICEMAIL_PROVIDER_KEY = "button_voicemail_provider_key";
     private static final String BUTTON_VOICEMAIL_SETTING_KEY = "button_voicemail_setting_key";
@@ -251,6 +252,7 @@
     private ListPreference mButtonTTY;
     private Preference mPhoneAccountSettingsPreference;
     private ListPreference mVoicemailProviders;
+    private PreferenceScreen mVoicemailSettingsScreen;
     private PreferenceScreen mVoicemailSettings;
     private Preference mVoicemailNotificationRingtone;
     private CheckBoxPreference mVoicemailNotificationVibrate;
@@ -483,6 +485,7 @@
             mAudioManager.setParameter(HAC_KEY, hac != 0 ? HAC_VAL_ON : HAC_VAL_OFF);
             return true;
         } else if (preference == mVoicemailSettings) {
+            mVoicemailSettings.getDialog().getActionBar().setDisplayHomeAsUpEnabled(false);
             if (DBG) log("onPreferenceTreeClick: Voicemail Settings Preference is clicked.");
             if (preference.getIntent() != null) {
                 if (DBG) {
@@ -507,6 +510,9 @@
                 // This should let the preference use default behavior in the xml.
                 return false;
             }
+        } else if (preference == mVoicemailSettingsScreen) {
+            mVoicemailSettingsScreen.getDialog().getActionBar().setDisplayHomeAsUpEnabled(false);
+            return false;
         }
         return false;
     }
@@ -1550,6 +1556,8 @@
 
         if (mVoicemailProviders != null) {
             mVoicemailProviders.setOnPreferenceChangeListener(this);
+            mVoicemailSettingsScreen =
+                    (PreferenceScreen) findPreference(VOICEMAIL_SETTING_SCREEN_PREF_KEY);
             mVoicemailSettings = (PreferenceScreen)findPreference(BUTTON_VOICEMAIL_SETTING_KEY);
             mVoicemailNotificationRingtone =
                     findPreference(BUTTON_VOICEMAIL_NOTIFICATION_RINGTONE_KEY);
@@ -1647,12 +1655,6 @@
         updateVoiceNumberField();
         mVMProviderSettingsForced = false;
 
-        if (SipUtil.isVoipSupported(this)) {
-            addPreferencesFromResource(
-                    com.android.services.telephony.sip.R.xml.sip_settings_category);
-        }
-
-
         if (mButtonDTMF != null) {
             int dtmf = Settings.System.getInt(getContentResolver(),
                     Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, Constants.DTMF_TONE_TYPE_NORMAL);
@@ -2032,7 +2034,6 @@
         }
         return super.onOptionsItemSelected(item);
     }
-
     /**
      * Finish current Activity and go up to the top level Settings ({@link CallFeaturesSetting}).
      * This is useful for implementing "HomeAsUp" capability for second-level Settings.
diff --git a/src/com/android/phone/HfaActivity.java b/src/com/android/phone/HfaActivity.java
index bcd3652..b526d46 100644
--- a/src/com/android/phone/HfaActivity.java
+++ b/src/com/android/phone/HfaActivity.java
@@ -81,7 +81,7 @@
     }
 
     private void buildAndShowDialog() {
-        mDialog = new AlertDialog.Builder(this)
+        mDialog = new AlertDialog.Builder(this, AlertDialog.THEME_DEVICE_DEFAULT_LIGHT)
                 .setTitle(R.string.ota_hfa_activation_title)
                 .setMessage(R.string.ota_hfa_activation_dialog_message)
                 .setPositiveButton(R.string.ota_skip_activation_dialog_skip_label,
@@ -108,7 +108,8 @@
     private void onHfaError(String errorMsg) {
         mDialog.dismiss();
 
-        AlertDialog errorDialog = new AlertDialog.Builder(this)
+        AlertDialog errorDialog = new AlertDialog.Builder(this,
+                AlertDialog.THEME_DEVICE_DEFAULT_LIGHT)
             .setMessage(errorMsg)
             .setPositiveButton(R.string.ota_skip_activation_dialog_skip_label,
                     new DialogInterface.OnClickListener() {
diff --git a/src/com/android/phone/OtaStartupReceiver.java b/src/com/android/phone/OtaStartupReceiver.java
index 594b63a..09cb185 100644
--- a/src/com/android/phone/OtaStartupReceiver.java
+++ b/src/com/android/phone/OtaStartupReceiver.java
@@ -31,6 +31,7 @@
 import android.telephony.TelephonyManager;
 
 import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.TelephonyCapabilities;
 
 import android.util.Log;
@@ -47,18 +48,23 @@
     private static final int SERVICE_STATE_CHANGED = 11;
     private Context mContext;
 
-    /**
-     * For debug purposes we're listening for otaspChanged events as
-     * this may be be used in the future for deciding if OTASP is
-     * necessary.
-     */
     private int mOtaspMode = -1;
     private boolean mPhoneStateListenerRegistered = false;
     private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
         @Override
         public void onOtaspChanged(int otaspMode) {
+            if (mOtaspMode == otaspMode) {
+                return;
+            }
             mOtaspMode = otaspMode;
             Log.v(TAG, "onOtaspChanged: mOtaspMode=" + mOtaspMode);
+
+            if (otaspMode == ServiceStateTracker.OTASP_NEEDED) {
+                Log.i(TAG, "OTASP is needed - performing CDMA provisioning");
+                final Intent intent = new Intent(OtaUtils.ACTION_PERFORM_CDMA_PROVISIONING);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                mContext.startActivity(intent);
+            }
         }
     };
 
@@ -111,11 +117,6 @@
             return;
         }
 
-        if (!TelephonyCapabilities.supportsOtasp(PhoneGlobals.getPhone())) {
-            if (DBG) Log.d(TAG, "OTASP not supported, nothing to do.");
-            return;
-        }
-
         if (mPhoneStateListenerRegistered == false) {
             if (DBG) Log.d(TAG, "Register our PhoneStateListener");
             TelephonyManager telephonyManager = (TelephonyManager)context.getSystemService(
@@ -126,6 +127,11 @@
             if (DBG) Log.d(TAG, "PhoneStateListener already registered");
         }
 
+        if (!TelephonyCapabilities.supportsOtasp(PhoneGlobals.getPhone())) {
+            if (DBG) Log.d(TAG, "OTASP not supported, nothing to do.");
+            return;
+        }
+
         if (shouldPostpone(context)) {
             if (DBG) Log.d(TAG, "Postponing OTASP until wizard runs");
             return;
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index b2e1332..4dd8ee2 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -143,7 +143,6 @@
     private BluetoothManager bluetoothManager;
     private CallGatewayManager callGatewayManager;
     private CallStateMonitor callStateMonitor;
-    private IBluetoothHeadsetPhone mBluetoothPhone;
 
     static int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
     static boolean sVoiceCapable = true;
@@ -350,17 +349,6 @@
                 cdmaPhoneCallState.CdmaPhoneCallStateInit();
             }
 
-            if (BluetoothAdapter.getDefaultAdapter() != null) {
-                // Start BluetoothPhoneService even if device is not voice capable.
-                // The device can still support VOIP.
-                startService(new Intent(this, BluetoothPhoneService.class));
-                bindService(new Intent(this, BluetoothPhoneService.class),
-                            mBluetoothPhoneConnection, 0);
-            } else {
-                // Device is not bluetooth capable
-                mBluetoothPhone = null;
-            }
-
             // before registering for phone state changes
             mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
             mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, LOG_TAG);
@@ -499,10 +487,6 @@
         return getInstance().phone;
     }
 
-    IBluetoothHeadsetPhone getBluetoothPhoneService() {
-        return mBluetoothPhone;
-    }
-
     /* package */ BluetoothManager getBluetoothManager() {
         return bluetoothManager;
     }
@@ -797,14 +781,6 @@
         notifier.updateCallNotifierRegistrationsAfterRadioTechnologyChange();
         callStateMonitor.updateAfterRadioTechnologyChange();
 
-        if (mBluetoothPhone != null) {
-            try {
-                mBluetoothPhone.updateBtHandsfreeAfterRadioTechnologyChange();
-            } catch (RemoteException e) {
-                Log.e(LOG_TAG, Log.getStackTraceString(new Throwable()));
-            }
-        }
-
         // Update registration for ICC status after radio technology change
         IccCard sim = phone.getIccCard();
         if (sim != null) {
@@ -967,21 +943,4 @@
      * Used to determine if the preserved call origin is fresh enough.
      */
     private static final long CALL_ORIGIN_EXPIRATION_MILLIS = 30 * 1000;
-
-    /** Service connection */
-    private final ServiceConnection mBluetoothPhoneConnection = new ServiceConnection() {
-
-        /** Handle the task of binding the local object to the service */
-        public void onServiceConnected(ComponentName className, IBinder service) {
-            Log.i(LOG_TAG, "Headset phone created, binding local service.");
-            mBluetoothPhone = IBluetoothHeadsetPhone.Stub.asInterface(service);
-        }
-
-        /** Handle the task of cleaning up the local binding */
-        public void onServiceDisconnected(ComponentName className) {
-            Log.i(LOG_TAG, "Headset phone disconnected, cleaning local binding.");
-            mBluetoothPhone = null;
-        }
-    };
-
 }
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index fa3d18b..56d26c9 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -227,19 +227,7 @@
                         // should be allowed to add another call in case one of the parties
                         // drops off
                         app.cdmaPhoneCallState.setAddCallMenuStateAfterCallWaiting(true);
-
-                        // If a BluetoothPhoneService is valid we need to set the second call state
-                        // so that the Bluetooth client can update the Call state correctly when
-                        // a call waiting is answered from the Phone.
-                        btPhone = app.getBluetoothPhoneService();
-                        if (btPhone != null) {
-                            try {
-                                btPhone.cdmaSetSecondCallState(true);
-                            } catch (RemoteException e) {
-                                Log.e(LOG_TAG, Log.getStackTraceString(new Throwable()));
-                            }
-                        }
-                  }
+                    }
                 }
 
                 final boolean isRealIncomingCall = isRealIncomingCall(ringingCall.getState());
@@ -737,20 +725,6 @@
         // In the future we may provide some way for user to choose among
         // multiple background calls, for now, always act on the first background call.
         PhoneUtils.switchHoldingAndActive(mApp.mCM.getFirstActiveBgCall());
-
-        // If we have a valid BluetoothPhoneService then since CDMA network or
-        // Telephony FW does not send us information on which caller got swapped
-        // we need to update the second call active state in BluetoothPhoneService internally
-        if (mApp.mCM.getBgPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
-            final IBluetoothHeadsetPhone btPhone = mApp.getBluetoothPhoneService();
-            if (btPhone != null) {
-                try {
-                    btPhone.cdmaSwapSecondCallState();
-                } catch (RemoteException e) {
-                    Log.e(LOG_TAG, Log.getStackTraceString(new Throwable()));
-                }
-            }
-        }
     }
 
     /**
diff --git a/src/com/android/phone/settings/PhoneAccountSettingsFragment.java b/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
index fb6365e..2a14f0b 100644
--- a/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
+++ b/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
@@ -2,22 +2,18 @@
 
 import android.content.ActivityNotFoundException;
 import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.net.sip.SipManager;
-import android.net.sip.SipProfile;
 import android.os.Bundle;
 import android.preference.CheckBoxPreference;
 import android.preference.ListPreference;
 import android.preference.Preference;
 import android.preference.PreferenceFragment;
-import android.preference.PreferenceScreen;
-import android.preference.SwitchPreference;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.util.Log;
 
 import com.android.phone.R;
+import com.android.services.telephony.sip.SipAccountRegistry;
 import com.android.services.telephony.sip.SipSharedPreferences;
 import com.android.services.telephony.sip.SipUtil;
 
@@ -43,6 +39,7 @@
 
     private static final String SIP_SETTINGS_CATEGORY_PREF_KEY = "phone_accounts_sip_settings_key";
     private static final String USE_SIP_PREF_KEY = "use_sip_calling_options_key";
+    private static final String SIP_RECEIVE_CALLS_PREF_KEY = "sip_receive_calls_key";
 
     private String LOG_TAG = PhoneAccountSettingsFragment.class.getSimpleName();
 
@@ -53,6 +50,7 @@
     private Preference mConfigureCallAssistant;
 
     private ListPreference mUseSipCalling;
+    private CheckBoxPreference mSipReceiveCallsPreference;
     private SipSharedPreferences mSipSharedPreferences;
 
     @Override
@@ -72,9 +70,9 @@
 
         addPreferencesFromResource(com.android.phone.R.xml.phone_account_settings);
 
+        mDefaultOutgoingAccount = (AccountSelectionPreference)
+                getPreferenceScreen().findPreference(DEFAULT_OUTGOING_ACCOUNT_KEY);
         if (mTelecomManager.getAllPhoneAccountsCount() > 1) {
-            mDefaultOutgoingAccount = (AccountSelectionPreference)
-                    getPreferenceScreen().findPreference(DEFAULT_OUTGOING_ACCOUNT_KEY);
             mDefaultOutgoingAccount.setListener(this);
             updateDefaultOutgoingAccountsModel();
         } else {
@@ -109,6 +107,13 @@
             mUseSipCalling.setValueIndex(
                     mUseSipCalling.findIndexOfValue(mSipSharedPreferences.getSipCallOption()));
             mUseSipCalling.setSummary(mUseSipCalling.getEntry());
+
+            mSipReceiveCallsPreference = (CheckBoxPreference)
+                    getPreferenceScreen().findPreference(SIP_RECEIVE_CALLS_PREF_KEY);
+            mSipReceiveCallsPreference.setEnabled(SipUtil.isPhoneIdle(getActivity()));
+            mSipReceiveCallsPreference.setChecked(
+                    mSipSharedPreferences.isReceivingCallsEnabled());
+            mSipReceiveCallsPreference.setOnPreferenceChangeListener(this);
         } else {
             getPreferenceScreen().removePreference(
                     getPreferenceScreen().findPreference(SIP_SETTINGS_CATEGORY_PREF_KEY));
@@ -116,8 +121,7 @@
     }
 
     /**
-     * Handles changes to the preferences, namely the switch which controls whether to use the call
-     * assistant or not.
+     * Handles changes to the preferences.
      *
      * @param pref The preference changed.
      * @param objValue The changed value.
@@ -131,6 +135,14 @@
             mUseSipCalling.setValueIndex(mUseSipCalling.findIndexOfValue(option));
             mUseSipCalling.setSummary(mUseSipCalling.getEntry());
             return true;
+        } else if (pref == mSipReceiveCallsPreference) {
+            final boolean isEnabled = !mSipReceiveCallsPreference.isChecked();
+            new Thread(new Runnable() {
+                public void run() {
+                    handleSipReceiveCallsOption(isEnabled);
+                }
+            }).start();
+            return true;
         }
         return false;
     }
@@ -191,6 +203,16 @@
         }
     }
 
+    private synchronized void handleSipReceiveCallsOption(boolean isEnabled) {
+        mSipSharedPreferences.setReceivingCallsEnabled(isEnabled);
+
+        SipUtil.useSipToReceiveIncomingCalls(getActivity(), isEnabled);
+
+        // Restart all Sip services to ensure we reflect whether we are receiving calls.
+        SipAccountRegistry sipAccountRegistry = SipAccountRegistry.getInstance();
+        sipAccountRegistry.restartSipService(getActivity());
+    }
+
     /**
      * Queries the telcomm manager to update the default outgoing account selection preference
      * with the list of outgoing accounts and the current default outgoing account.
@@ -213,7 +235,7 @@
                 mTelecomManager,
                 simCallManagers,
                 mTelecomManager.getSimCallManager(),
-                getString(R.string.wifi_calling_do_not_use_call_assistant));
+                getString(R.string.wifi_calling_call_assistant_none));
 
         updateConfigureCallAssistantSummary();
     }