Merge "Add getCdmaMdn and getCdmaMin to phoneinterfacemanager." into lmp-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index fe79017..7add3a8 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -40,7 +40,6 @@
     <protected-broadcast android:name="com.android.internal.telephony.data-restart-trysetup" />
     <protected-broadcast android:name="com.android.internal.telephony.data-stall" />
 
-    <uses-permission android:name="android.permission.BIND_CALL_SERVICE" />
     <uses-permission android:name="android.permission.BROADCAST_STICKY" />
     <uses-permission android:name="android.permission.CALL_PHONE" />
     <uses-permission android:name="android.permission.CALL_PRIVILEGED" />
@@ -479,7 +478,8 @@
         </service>
         <service android:name="com.android.services.telephony.sip.SipConnectionService"
                  android:label="@string/sip_connection_service_label"
-                 android:singleUser="true" >
+                 android:singleUser="true"
+                 android:permission="android.permission.BIND_CONNECTION_SERVICE" >
             <intent-filter>
                 <action android:name="android.telecomm.ConnectionService" />
             </intent-filter>
@@ -572,7 +572,8 @@
         <service
                 android:singleUser="true"
                 android:name="com.android.services.telephony.TelephonyConnectionService"
-                android:label="@string/pstn_connection_service_label">
+                android:label="@string/pstn_connection_service_label"
+                android:permission="android.permission.BIND_CONNECTION_SERVICE" >
             <intent-filter>
                 <action android:name="android.telecomm.ConnectionService" />
             </intent-filter>
diff --git a/res/values/config.xml b/res/values/config.xml
index 0d1ae54..cfca00b 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -121,7 +121,7 @@
     <!-- Show cdma auto network mode in (glabal) roaming -->
     <bool name="config_show_cdma" translatable="false">false</bool>
     <!-- Display enhanced 4G LTE mode menu if true -->
-    <bool name="config_enhanced_4g_lte_mode_enable" translatable="false">true</bool>
+    <bool name="config_enhanced_4g_lte_mode_enable" translatable="false">false</bool>
 
     <!-- Package name for the default in-call UI and dialer [DO NOT TRANSLATE] -->
     <string name="ui_default_package" translatable="false">com.android.dialer</string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c343deb..0745ad7 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1139,11 +1139,6 @@
          on this device. [CHAR LIMIT=40] -->
     <string name="not_voice_capable">Voice calling not supported</string>
 
-    <!-- Title of settings screen for managing the "Respond via SMS" feature. [CHAR LIMIT=30] -->
-    <string name="respond_via_sms_setting_title">Quick responses</string>
-    <!-- Settings summary string for the "Respond via SMS" feature. [CHAR LIMIT=40] -->
-    <string name="respond_via_sms_setting_summary"></string>
-
     <!-- String describing the Dial ImageButton
 
          Used by AccessibilityService to announce the purpose of the button.
@@ -1161,12 +1156,6 @@
          [CHAR LIMIT=30] -->
     <string name="voicemail_notification_ringtone_title">Sound</string>
 
-    <!--  The string used to describe a notification if it is the default one in the system. For
-          example, if the user selects the default notification, it will appear as something like
-          Default sound(Capella) in the notification summary.
-          [CHAR LIMIT=40] -->
-    <string name="default_notification_description">Default sound (<xliff:g id="default_sound_title">%1$s</xliff:g>)</string>
-
     <!-- The default value value for voicemail notification. -->
     <string name="voicemail_notification_vibrate_when_default" translatable="false">never</string>
 
@@ -1177,18 +1166,6 @@
         <item>never</item>
     </string-array>
 
-    <!-- Setting option name to pick ringtone (a list dialog comes up). [CHAR LIMIT=30] -->
-    <string name="ringtone_title" msgid="5379026328015343686">Phone ringtone</string>
-
-    <!-- Setting option name to enable or disable vibration when ringing
-         the phone.
-         [CHAR LIMIT=30] -->
-    <string name="vibrate_on_ring_title">Vibrate when ringing</string>
-
-    <!-- Setting option name to enable or disable DTMF tone sound
-         [CHAR LIMIT=30] -->
-    <string name="dtmf_tone_enable_title">Dial pad touch tones</string>
-
     <!--  Setting option name to enable or disable dialpad autocomplete functionality
          [CHAR LIMIT=30] -->
     <string name="dial_pad_autocomplete">Dial pad autocomplete</string>
diff --git a/res/xml/call_feature_setting.xml b/res/xml/call_feature_setting.xml
index 30811e4..625ff4c 100644
--- a/res/xml/call_feature_setting.xml
+++ b/res/xml/call_feature_setting.xml
@@ -17,110 +17,77 @@
     xmlns:phone="http://schemas.android.com/apk/res/com.android.phone"
     android:title="@string/call_settings">
 
-    <PreferenceCategory
-        android:key="button_ringtone_category_key"
-        android:title="@string/preference_category_ringtone"
-        android:persistent="false">
-
-        <com.android.phone.DefaultRingtonePreference
-            android:key="button_ringtone_key"
-            android:title="@string/ringtone_title"
-            android:dialogTitle="@string/ringtone_title"
-            android:persistent="false"
-            android:ringtoneType="ringtone" />
-
-        <CheckBoxPreference
-            android:key="button_vibrate_on_ring"
-            android:title="@string/vibrate_on_ring_title"
-            android:persistent="false"
-            android:defaultValue="false" />
-    </PreferenceCategory>
-
-  <PreferenceCategory
-      android:key="button_misc_category_key"
-      android:title="@string/other_settings"
-      android:persistent="false" />
-
     <Preference
-            android:key="phone_accounts"
-            android:title="@string/phone_accounts" >
+        android:key="phone_accounts"
+        android:title="@string/phone_accounts">
+
         <intent
-                android:targetClass="com.android.telecomm.PhoneAccountPreferencesActivity"
-                android:targetPackage="com.android.telecomm" />
+            android:targetClass="com.android.telecomm.PhoneAccountPreferencesActivity"
+            android:targetPackage="com.android.telecomm" />
+
     </Preference>
 
-  <PreferenceScreen
-      android:key="button_voicemail_category_key"
-      android:title="@string/voicemail"
-      android:persistent="false">
-      <ListPreference
-          android:key="button_voicemail_provider_key"
-          android:title="@string/voicemail_provider"
-          android:summary="@string/sum_voicemail_choose_provider"
-          android:defaultValue=""
-          android:persistent="true" />
-      <PreferenceScreen
-          android:key="button_voicemail_setting_key"
-          android:title="@string/voicemail_settings"
-          android:persistent="false">
+    <PreferenceScreen
+        android:key="button_voicemail_category_key"
+        android:title="@string/voicemail"
+        android:persistent="false">
 
-          <!-- Note for all com.android.phone.EditPhoneNumberPreference objects
+        <ListPreference
+            android:key="button_voicemail_provider_key"
+            android:title="@string/voicemail_provider"
+            android:summary="@string/sum_voicemail_choose_provider"
+            android:defaultValue=""
+            android:persistent="true" />
 
-               The last several attributes are for use with the EditText field
-               in the dialog.  These attributes are forwarded to that field
-               when the edittext is created.  The attributes include:
-               1. android:singleLine
-               2. android:autoText
-               3. android:background -->
+        <PreferenceScreen
+            android:key="button_voicemail_setting_key"
+            android:title="@string/voicemail_settings"
+            android:persistent="false">
 
-          <com.android.phone.EditPhoneNumberPreference
-              android:key="button_voicemail_key"
-              android:title="@string/voicemail_settings_number_label"
-              android:persistent="false"
-              android:dialogTitle="@string/voicemail"
-              phone:confirmMode="confirm"
-              android:singleLine="true"
-              android:autoText="false" />
-      </PreferenceScreen>
+            <!-- Note for all com.android.phone.EditPhoneNumberPreference objects
 
-      <RingtonePreference
-          android:key="button_voicemail_notification_ringtone_key"
-          android:title="@string/voicemail_notification_ringtone_title"
-          android:persistent="true"
-          android:ringtoneType="notification"
-          android:defaultValue="content://settings/system/notification_sound" />
-      <CheckBoxPreference
-          android:key="button_voicemail_notification_vibrate_key"
-          android:title="@string/voicemail_notification_vibrate_when_title"
-          android:persistent="true"
-          />
-  </PreferenceScreen>
+                 The last several attributes are for use with the EditText field
+                 in the dialog.  These attributes are forwarded to that field
+                 when the edittext is created.  The attributes include:
+                 1. android:singleLine
+                 2. android:autoText
+                 3. android:background -->
 
-  <CheckBoxPreference
-      android:key="button_play_dtmf_tone"
-      android:title="@string/dtmf_tone_enable_title"
-      android:persistent="false"
-      android:defaultValue="true" />
+            <com.android.phone.EditPhoneNumberPreference
+                android:key="button_voicemail_key"
+                android:title="@string/voicemail_settings_number_label"
+                android:persistent="false"
+                android:dialogTitle="@string/voicemail"
+                phone:confirmMode="confirm"
+                android:singleLine="true"
+                android:autoText="false" />
 
-  <PreferenceScreen
-      android:key="button_respond_via_sms_key"
-      android:title="@string/respond_via_sms_setting_title"
-      android:summary="@string/respond_via_sms_setting_summary"
-      android:persistent="false">
-      <intent
-          android:action="android.intent.action.MAIN"
-          android:targetPackage="com.android.telecomm"
-          android:targetClass="com.android.telecomm.RespondViaSmsSettings$Settings" />
-  </PreferenceScreen>
+        </PreferenceScreen>
 
-  <PreferenceScreen
-      android:key="button_fdn_key"
-      android:title="@string/fdn"
-      android:persistent="false">
-      <intent android:action="android.intent.action.MAIN"
-          android:targetPackage="com.android.phone"
-          android:targetClass="com.android.phone.FdnSetting" />
-  </PreferenceScreen>
+        <RingtonePreference
+            android:key="button_voicemail_notification_ringtone_key"
+            android:title="@string/voicemail_notification_ringtone_title"
+            android:persistent="true"
+            android:ringtoneType="notification"
+            android:defaultValue="content://settings/system/notification_sound" />
+
+        <CheckBoxPreference
+            android:key="button_voicemail_notification_vibrate_key"
+            android:title="@string/voicemail_notification_vibrate_when_title"
+            android:persistent="true" />
+
+    </PreferenceScreen>
+
+    <PreferenceScreen
+        android:key="button_fdn_key"
+        android:title="@string/fdn"
+        android:persistent="false">
+
+        <intent android:action="android.intent.action.MAIN"
+            android:targetPackage="com.android.phone"
+            android:targetClass="com.android.phone.FdnSetting" />
+
+    </PreferenceScreen>
 
     <CheckBoxPreference
         android:key="button_auto_retry_key"
@@ -136,7 +103,7 @@
         android:entries="@array/tty_mode_entries"
         android:entryValues="@array/tty_mode_values"/>
 
-     <CheckBoxPreference
+    <CheckBoxPreference
         android:key="button_hac_key"
         android:title="@string/hac_mode_title"
         android:persistent="true"
@@ -158,6 +125,7 @@
         <intent android:action="android.intent.action.MAIN"
             android:targetPackage="com.android.phone"
             android:targetClass="com.android.phone.GsmUmtsCallOptions"/>
+
     </PreferenceScreen>
 
     <PreferenceScreen
@@ -169,6 +137,7 @@
         <intent android:action="android.intent.action.MAIN"
             android:targetPackage="com.android.phone"
             android:targetClass="com.android.phone.CdmaCallOptions"/>
+
     </PreferenceScreen>
 
     <CheckBoxPreference
@@ -176,4 +145,5 @@
         android:title="@string/enable_video_calling_title"
         android:persistent="true"
         android:defaultValue="true" />
+
 </PreferenceScreen>
diff --git a/res/xml/gsm_umts_options.xml b/res/xml/gsm_umts_options.xml
index 1156f91..3f85ea8 100644
--- a/res/xml/gsm_umts_options.xml
+++ b/res/xml/gsm_umts_options.xml
@@ -22,7 +22,7 @@
         android:title="@string/apn_settings"
         android:persistent="false">
 
-        <intent android:action="android.settings.APN_SETTINGS" />
+        <!-- The launching Intent will be defined thru code as we need to pass some Extra -->
 
     </PreferenceScreen>
 
diff --git a/sip/res/xml/sip_settings_category.xml b/sip/res/xml/sip_settings_category.xml
index 17ee577..9527d6a 100644
--- a/sip/res/xml/sip_settings_category.xml
+++ b/sip/res/xml/sip_settings_category.xml
@@ -15,34 +15,38 @@
 -->
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:phone="http://schemas.android.com/apk/res/com.android.phone">
-    <PreferenceCategory
-            android:key="sip_settings_category_key"
-            android:title="@string/sip_settings"
+
+    <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">
 
-        <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" />
 
-            <intent android:action="android.intent.action.MAIN"
-                    android:targetPackage="com.android.phone"
-                    android:targetClass="com.android.services.telephony.sip.SipSettings" />
-        </PreferenceScreen>
+    </PreferenceScreen>
 
-        <ListPreference
-                android:key="sip_call_options_key"
-                android:title="@string/sip_call_options_title"
-                android:persistent="true"
-                android:entries="@array/sip_call_options_entries"
-                android:entryValues="@array/sip_call_options_values"/>
+    <ListPreference
+            android:key="sip_call_options_key"
+            android:title="@string/sip_call_options_title"
+            android:persistent="true"
+            android:entries="@array/sip_call_options_entries"
+            android:entryValues="@array/sip_call_options_values"/>
 
-        <ListPreference
-                android:key="sip_call_options_wifi_only_key"
-                android:title="@string/sip_call_options_title"
-                android:dialogTitle="@string/sip_call_options_wifi_only_title"
-                android:persistent="true"
-                android:entries="@array/sip_call_options_wifi_only_entries"
-                android:entryValues="@array/sip_call_options_values"/>
-    </PreferenceCategory>
+    <ListPreference
+            android:key="sip_call_options_wifi_only_key"
+            android:title="@string/sip_call_options_title"
+            android:dialogTitle="@string/sip_call_options_wifi_only_title"
+            android:persistent="true"
+            android:entries="@array/sip_call_options_wifi_only_entries"
+            android:entryValues="@array/sip_call_options_values"/>
+
+    </PreferenceScreen>
+
 </PreferenceScreen>
diff --git a/sip/src/com/android/services/telephony/sip/SipConnection.java b/sip/src/com/android/services/telephony/sip/SipConnection.java
index 58db1f5..2603b98 100644
--- a/sip/src/com/android/services/telephony/sip/SipConnection.java
+++ b/sip/src/com/android/services/telephony/sip/SipConnection.java
@@ -180,11 +180,6 @@
     }
 
     @Override
-    public void onChildrenChanged(List<Connection> children) {
-        if (VERBOSE) log("onChildrenChanged, children: " + children);
-    }
-
-    @Override
     public void onPhoneAccountClicked() {
         if (VERBOSE) log("onPhoneAccountClicked");
     }
diff --git a/sip/src/com/android/services/telephony/sip/SipConnectionService.java b/sip/src/com/android/services/telephony/sip/SipConnectionService.java
index bda564f..8f11935 100644
--- a/sip/src/com/android/services/telephony/sip/SipConnectionService.java
+++ b/sip/src/com/android/services/telephony/sip/SipConnectionService.java
@@ -61,7 +61,7 @@
                 com.android.internal.telephony.Connection chosenConnection =
                         createConnectionForProfile(profile, request);
                 if (chosenConnection == null) {
-                    connection.setCanceled();
+                    connection.setDisconnected(DisconnectCause.OUTGOING_CANCELED, null);
                 } else {
                     connection.initialize(chosenConnection);
                 }
@@ -70,13 +70,13 @@
             @Override
             public void onSipNotChosen() {
                 if (VERBOSE) log("onCreateOutgoingConnection, onSipNotChosen");
-                connection.setFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
+                connection.setDisconnected(DisconnectCause.ERROR_UNSPECIFIED, null);
             }
 
             @Override
             public void onCancelCall() {
                 if (VERBOSE) log("onCreateOutgoingConnection, onCancelCall");
-                connection.setCanceled();
+                connection.setDisconnected(DisconnectCause.OUTGOING_CANCELED, null);
             }
         };
 
@@ -87,14 +87,6 @@
     }
 
     @Override
-    public void onCreateConferenceConnection(
-            String token,
-            Connection connection,
-            Response<String, Connection> response) {
-        if (VERBOSE) log("onCreateConferenceConnection, connection: " + connection);
-    }
-
-    @Override
     public Connection onCreateIncomingConnection(
             PhoneAccountHandle connectionManagerAccount,
             ConnectionRequest request) {
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index 9f0dad7..103606a 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -34,27 +34,21 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.database.Cursor;
-import android.database.sqlite.SQLiteException;
 import android.media.AudioManager;
 import android.media.RingtoneManager;
-import android.net.Uri;
 import android.net.sip.SipManager;
 import android.os.AsyncResult;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
 import android.os.UserHandle;
-import android.os.Vibrator;
 import android.preference.CheckBoxPreference;
 import android.preference.ListPreference;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
-import android.preference.PreferenceCategory;
-import android.preference.PreferenceGroup;
 import android.preference.PreferenceManager;
 import android.preference.PreferenceScreen;
 import android.provider.ContactsContract.CommonDataKinds;
-import android.provider.MediaStore;
 import android.provider.Settings;
 import android.telecomm.ConnectionService;
 import android.telecomm.TelecommManager;
@@ -69,9 +63,11 @@
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
+import com.android.phone.common.util.SettingsUtil;
 import com.android.services.telephony.sip.SipSharedPreferences;
 import com.android.services.telephony.sip.SipUtil;
 
+import java.lang.String;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -95,14 +91,16 @@
  * For the "Mobile network settings" screen under the main Settings app,
  * See {@link MobileNetworkSettings}.
  *
+ * TODO: Settings should be split into PreferenceFragments where possible (ie. voicemail, SIP).
+ *
  * @see com.android.phone.MobileNetworkSettings
  */
 public class CallFeaturesSetting extends PreferenceActivity
         implements DialogInterface.OnClickListener,
-        Preference.OnPreferenceChangeListener,
-        Preference.OnPreferenceClickListener,
-        EditPhoneNumberPreference.OnDialogClosedListener,
-        EditPhoneNumberPreference.GetDefaultNumberListener {
+                Preference.OnPreferenceChangeListener,
+                Preference.OnPreferenceClickListener,
+                EditPhoneNumberPreference.OnDialogClosedListener,
+                EditPhoneNumberPreference.GetDefaultNumberListener {
     private static final String LOG_TAG = "CallFeaturesSetting";
     private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
@@ -176,13 +174,7 @@
     /* package */ static final String BUTTON_VOICEMAIL_NOTIFICATION_RINGTONE_KEY =
             "button_voicemail_notification_ringtone_key";
     private static final String BUTTON_FDN_KEY   = "button_fdn_key";
-    private static final String BUTTON_RESPOND_VIA_SMS_KEY   = "button_respond_via_sms_key";
 
-    private static final String BUTTON_RINGTONE_CATEGORY = "button_ringtone_category_key";
-
-    private static final String BUTTON_RINGTONE_KEY    = "button_ringtone_key";
-    private static final String BUTTON_VIBRATE_ON_RING = "button_vibrate_on_ring";
-    private static final String BUTTON_PLAY_DTMF_TONE  = "button_play_dtmf_tone";
     private static final String BUTTON_DTMF_KEY        = "button_dtmf_settings";
     private static final String BUTTON_RETRY_KEY       = "button_auto_retry_key";
     private static final String BUTTON_TTY_KEY         = "button_tty_mode_key";
@@ -193,12 +185,11 @@
 
     private static final String VM_NUMBERS_SHARED_PREFERENCES_NAME = "vm_numbers";
 
-    private static final String BUTTON_SIP_CALL_OPTIONS =
-            "sip_call_options_key";
+    private static final String BUTTON_SIP_CALL_OPTIONS = "sip_call_options_key";
     private static final String BUTTON_SIP_CALL_OPTIONS_WIFI_ONLY =
             "sip_call_options_wifi_only_key";
-    private static final String SIP_SETTINGS_CATEGORY_KEY =
-            "sip_settings_category_key";
+    private static final String SIP_SETTINGS_PREFERENCE_SCREEN_KEY =
+            "sip_settings_preference_screen_key";
 
     private Intent mContactListIntent;
 
@@ -207,8 +198,7 @@
     private static final int EVENT_FORWARDING_CHANGED       = 501;
     private static final int EVENT_FORWARDING_GET_COMPLETED = 502;
 
-    private static final int MSG_UPDATE_RINGTONE_SUMMARY = 1;
-    private static final int MSG_UPDATE_VOICEMAIL_RINGTONE_SUMMARY = 2;
+    private static final int MSG_UPDATE_VOICEMAIL_RINGTONE_SUMMARY = 1;
 
     public static final String HAC_KEY = "HACSetting";
     public static final String HAC_VAL_ON = "ON";
@@ -251,14 +241,11 @@
 
     private EditPhoneNumberPreference mSubMenuVoicemailSettings;
 
-    private Runnable mRingtoneLookupRunnable;
-    private final Handler mRingtoneLookupComplete = new Handler() {
+    private Runnable mVoicemailRingtoneLookupRunnable;
+    private final Handler mVoicemailRingtoneLookupComplete = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-                case MSG_UPDATE_RINGTONE_SUMMARY:
-                    mRingtonePreference.setSummary((CharSequence) msg.obj);
-                    break;
                 case MSG_UPDATE_VOICEMAIL_RINGTONE_SUMMARY:
                     mVoicemailNotificationRingtone.setSummary((CharSequence) msg.obj);
                     break;
@@ -266,10 +253,7 @@
         }
     };
 
-    private Preference mRingtonePreference;
-    private CheckBoxPreference mVibrateWhenRinging;
     /** Whether dialpad plays DTMF tone or not. */
-    private CheckBoxPreference mPlayDtmfTone;
     private CheckBoxPreference mButtonAutoRetry;
     private CheckBoxPreference mButtonHAC;
     private ListPreference mButtonDTMF;
@@ -489,9 +473,6 @@
     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
         if (preference == mSubMenuVoicemailSettings) {
             return true;
-        } else if (preference == mPlayDtmfTone) {
-            Settings.System.putInt(getContentResolver(), Settings.System.DTMF_TONE_WHEN_DIALING,
-                    mPlayDtmfTone.isChecked() ? 1 : 0);
         } else if (preference == mButtonDTMF) {
             return true;
         } else if (preference == mButtonTTY) {
@@ -553,11 +534,8 @@
             log("onPreferenceChange(). preferenece: \"" + preference + "\""
                     + ", value: \"" + objValue + "\"");
         }
-        if (preference == mVibrateWhenRinging) {
-            boolean doVibrate = (Boolean) objValue;
-            Settings.System.putInt(mPhone.getContext().getContentResolver(),
-                    Settings.System.VIBRATE_WHEN_RINGING, doVibrate ? 1 : 0);
-        } else if (preference == mButtonDTMF) {
+
+        if (preference == mButtonDTMF) {
             int index = mButtonDTMF.findIndexOfValue((String) objValue);
             Settings.System.putInt(mPhone.getContext().getContentResolver(),
                     Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, index);
@@ -1533,9 +1511,6 @@
             mSubMenuVoicemailSettings.setDialogTitle(R.string.voicemail_settings_number_label);
         }
 
-        mRingtonePreference = findPreference(BUTTON_RINGTONE_KEY);
-        mVibrateWhenRinging = (CheckBoxPreference) findPreference(BUTTON_VIBRATE_ON_RING);
-        mPlayDtmfTone = (CheckBoxPreference) findPreference(BUTTON_PLAY_DTMF_TONE);
         mButtonDTMF = (ListPreference) findPreference(BUTTON_DTMF_KEY);
         mButtonAutoRetry = (CheckBoxPreference) findPreference(BUTTON_RETRY_KEY);
         mButtonHAC = (CheckBoxPreference) findPreference(BUTTON_HAC_KEY);
@@ -1543,6 +1518,7 @@
         mConnectionService = (ListPreference)
                 findPreference(BUTTON_DEFAULT_CONNECTION_SERVICE);
         mVoicemailProviders = (ListPreference) findPreference(BUTTON_VOICEMAIL_PROVIDER_KEY);
+
         if (mVoicemailProviders != null) {
             mVoicemailProviders.setOnPreferenceChangeListener(this);
             mVoicemailSettings = (PreferenceScreen)findPreference(BUTTON_VOICEMAIL_SETTING_KEY);
@@ -1553,24 +1529,8 @@
             initVoiceMailProviders();
         }
 
-        if (mVibrateWhenRinging != null) {
-            Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
-            if (vibrator != null && vibrator.hasVibrator()) {
-                mVibrateWhenRinging.setOnPreferenceChangeListener(this);
-            } else {
-                PreferenceCategory ringToneCategory = (PreferenceCategory)findPreference(BUTTON_RINGTONE_CATEGORY);
-                ringToneCategory.removePreference(mVibrateWhenRinging);
-                mVibrateWhenRinging = null;
-            }
-        }
-
         final ContentResolver contentResolver = getContentResolver();
 
-        if (mPlayDtmfTone != null) {
-            mPlayDtmfTone.setChecked(Settings.System.getInt(contentResolver,
-                    Settings.System.DTMF_TONE_WHEN_DIALING, 1) != 0);
-        }
-
         if (mButtonDTMF != null) {
             if (getResources().getBoolean(R.bool.dtmf_type_enabled)) {
                 mButtonDTMF.setOnPreferenceChangeListener(this);
@@ -1611,23 +1571,25 @@
 
         if (!getResources().getBoolean(R.bool.world_phone)) {
             Preference options = prefSet.findPreference(BUTTON_CDMA_OPTIONS);
-            if (options != null)
+            if (options != null) {
                 prefSet.removePreference(options);
+            }
             options = prefSet.findPreference(BUTTON_GSM_UMTS_OPTIONS);
-            if (options != null)
+            if (options != null) {
                 prefSet.removePreference(options);
+            }
 
             int phoneType = mPhone.getPhoneType();
             if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
                 Preference fdnButton = prefSet.findPreference(BUTTON_FDN_KEY);
-                if (fdnButton != null)
+                if (fdnButton != null) {
                     prefSet.removePreference(fdnButton);
+                }
                 if (!getResources().getBoolean(R.bool.config_voice_privacy_disable)) {
                     addPreferencesFromResource(R.xml.cdma_call_privacy);
                 }
             } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
-                if (getResources().getBoolean(
-                            R.bool.config_additional_call_setting)) {
+                if (getResources().getBoolean(R.bool.config_additional_call_setting)) {
                     addPreferencesFromResource(R.xml.gsm_umts_call_options);
                 }
             } else {
@@ -1663,16 +1625,16 @@
         mVMProviderSettingsForced = false;
         createSipCallSettings();
 
-        mRingtoneLookupRunnable = new Runnable() {
+        mVoicemailRingtoneLookupRunnable = new Runnable() {
             @Override
             public void run() {
-                if (mRingtonePreference != null) {
-                    updateRingtoneName(RingtoneManager.TYPE_RINGTONE, mRingtonePreference,
-                            MSG_UPDATE_RINGTONE_SUMMARY);
-                }
                 if (mVoicemailNotificationRingtone != null) {
-                    updateRingtoneName(RingtoneManager.TYPE_NOTIFICATION,
-                            mVoicemailNotificationRingtone, MSG_UPDATE_VOICEMAIL_RINGTONE_SUMMARY);
+                    SettingsUtil.updateRingtoneName(
+                            mPhone.getContext(),
+                            mVoicemailRingtoneLookupComplete,
+                            RingtoneManager.TYPE_NOTIFICATION,
+                            mVoicemailNotificationRingtone,
+                            MSG_UPDATE_VOICEMAIL_RINGTONE_SUMMARY);
                 }
             }
         };
@@ -1692,65 +1654,6 @@
         }
     }
 
-    /**
-     * Updates ringtone name. This is a method copied from com.android.settings.SoundSettings
-     *
-     * @see com.android.settings.SoundSettings
-     */
-    private void updateRingtoneName(int type, Preference preference, int msg) {
-        if (preference == null) return;
-        final Uri ringtoneUri;
-        boolean defaultRingtone = false;
-        if (type == RingtoneManager.TYPE_RINGTONE) {
-            // For ringtones, we can just lookup the system default because changing the settings
-            // in Call Settings changes the system default.
-            ringtoneUri = RingtoneManager.getActualDefaultRingtoneUri(this, type);
-        } else {
-            final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
-                    mPhone.getContext());
-            // for voicemail notifications, we use the value saved in Phone's shared preferences.
-            String uriString = prefs.getString(preference.getKey(), null);
-            if (TextUtils.isEmpty(uriString)) {
-                // silent ringtone
-                ringtoneUri = null;
-            } else {
-                if (uriString.equals(Settings.System.DEFAULT_NOTIFICATION_URI.toString())) {
-                    // If it turns out that the voicemail notification is set to the system
-                    // default notification, we retrieve the actual URI to prevent it from showing
-                    // up as "Unknown Ringtone".
-                    defaultRingtone = true;
-                    ringtoneUri = RingtoneManager.getActualDefaultRingtoneUri(this, type);
-                } else {
-                    ringtoneUri = Uri.parse(uriString);
-                }
-            }
-        }
-        CharSequence summary = getString(com.android.internal.R.string.ringtone_unknown);
-        // Is it a silent ringtone?
-        if (ringtoneUri == null) {
-            summary = getString(com.android.internal.R.string.ringtone_silent);
-        } else {
-            // Fetch the ringtone title from the media provider
-            try {
-                Cursor cursor = getContentResolver().query(ringtoneUri,
-                        new String[] { MediaStore.Audio.Media.TITLE }, null, null, null);
-                if (cursor != null) {
-                    if (cursor.moveToFirst()) {
-                        summary = cursor.getString(0);
-                    }
-                    cursor.close();
-                }
-            } catch (SQLiteException sqle) {
-                // Unknown title for the ringtone
-            }
-        }
-        if (defaultRingtone) {
-            summary = mPhone.getContext().getString(
-                    R.string.default_notification_description, summary);
-        }
-        mRingtoneLookupComplete.sendMessage(mRingtoneLookupComplete.obtainMessage(msg, summary));
-    }
-
     private void createSipCallSettings() {
         // Add Internet call settings.
         if (SipUtil.isVoipSupported(this)) {
@@ -1779,8 +1682,8 @@
                 findPreference(BUTTON_SIP_CALL_OPTIONS);
         ListPreference wifiOnly = (ListPreference)
                 findPreference(BUTTON_SIP_CALL_OPTIONS_WIFI_ONLY);
-        PreferenceGroup sipSettings = (PreferenceGroup)
-                findPreference(SIP_SETTINGS_CATEGORY_KEY);
+        PreferenceScreen sipSettings = (PreferenceScreen)
+                getPreferenceScreen().findPreference(SIP_SETTINGS_PREFERENCE_SCREEN_KEY);
         if (SipManager.isSipWifiOnly(this)) {
             sipSettings.removePreference(wifiAnd3G);
             return wifiOnly;
@@ -1796,7 +1699,7 @@
         mForeground = true;
 
         if (isAirplaneModeOn()) {
-            Preference sipSettings = findPreference(SIP_SETTINGS_CATEGORY_KEY);
+            Preference sipSettings = findPreference(SIP_SETTINGS_PREFERENCE_SCREEN_KEY);
             PreferenceScreen screen = getPreferenceScreen();
             int count = screen.getPreferenceCount();
             for (int i = 0 ; i < count ; ++i) {
@@ -1806,10 +1709,6 @@
             return;
         }
 
-        if (mVibrateWhenRinging != null) {
-            mVibrateWhenRinging.setChecked(getVibrateWhenRinging(this));
-        }
-
         if (mButtonDTMF != null) {
             int dtmf = Settings.System.getInt(getContentResolver(),
                     Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, Constants.DTMF_TONE_TYPE_NORMAL);
@@ -1842,7 +1741,8 @@
                     BUTTON_VOICEMAIL_NOTIFICATION_VIBRATE_KEY, false));
         }
 
-        lookupRingtoneName();
+        // Look up the voicemail ringtone name asynchronously and update its preference.
+        new Thread(mVoicemailRingtoneLookupRunnable).start();
     }
 
     // Migrate settings from BUTTON_VOICEMAIL_NOTIFICATION_VIBRATE_WHEN_KEY to
@@ -1864,28 +1764,6 @@
         return false;
     }
 
-    /**
-     * Obtain the setting for "vibrate when ringing" setting.
-     *
-     * Watch out: if the setting is missing in the device, this will try obtaining the old
-     * "vibrate on ring" setting from AudioManager, and save the previous setting to the new one.
-     */
-    public static boolean getVibrateWhenRinging(Context context) {
-        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
-        if (vibrator == null || !vibrator.hasVibrator()) {
-            return false;
-        }
-        return Settings.System.getInt(context.getContentResolver(),
-                Settings.System.VIBRATE_WHEN_RINGING, 0) != 0;
-    }
-
-    /**
-     * Lookups ringtone name asynchronously and updates the relevant Preference.
-     */
-    private void lookupRingtoneName() {
-        new Thread(mRingtoneLookupRunnable).start();
-    }
-
     private boolean isAirplaneModeOn() {
         return Settings.System.getInt(getContentResolver(),
                 Settings.System.AIRPLANE_MODE_ON, 0) != 0;
diff --git a/src/com/android/phone/DefaultRingtonePreference.java b/src/com/android/phone/DefaultRingtonePreference.java
deleted file mode 100644
index 8205fd0..0000000
--- a/src/com/android/phone/DefaultRingtonePreference.java
+++ /dev/null
@@ -1,56 +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.content.Context;
-import android.content.Intent;
-import android.media.RingtoneManager;
-import android.net.Uri;
-import android.preference.RingtonePreference;
-import android.util.AttributeSet;
-
-/**
- * RingtonePreference which doesn't show default ringtone setting.
- *
- * @see com.android.settings.DefaultRingtonePreference
- */
-public class DefaultRingtonePreference extends RingtonePreference {
-    public DefaultRingtonePreference(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void onPrepareRingtonePickerIntent(Intent ringtonePickerIntent) {
-        super.onPrepareRingtonePickerIntent(ringtonePickerIntent);
-
-        /*
-         * Since this preference is for choosing the default ringtone, it
-         * doesn't make sense to show a 'Default' item.
-         */
-        ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, false);
-    }
-
-    @Override
-    protected void onSaveRingtone(Uri ringtoneUri) {
-        RingtoneManager.setActualDefaultRingtoneUri(getContext(), getRingtoneType(), ringtoneUri);
-    }
-
-    @Override
-    protected Uri onRestoreRingtone() {
-        return RingtoneManager.getActualDefaultRingtoneUri(getContext(), getRingtoneType());
-    }
-}
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index e84805f..bed49a9 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -44,6 +44,7 @@
 import android.widget.EditText;
 
 import com.android.phone.common.HapticFeedback;
+import com.android.phone.common.dialpad.DialpadKeyButton;
 import com.android.phone.common.util.ViewUtil;
 
 
@@ -65,7 +66,8 @@
  * also?
  */
 public class EmergencyDialer extends Activity implements View.OnClickListener,
-        View.OnLongClickListener, View.OnHoverListener, View.OnKeyListener, TextWatcher {
+        View.OnLongClickListener, View.OnKeyListener, TextWatcher,
+        DialpadKeyButton.OnPressedListener {
     // Keys used with onSaveInstanceState().
     private static final String LAST_NUMBER = "lastNumber";
 
@@ -287,9 +289,8 @@
     private void setupKeypad() {
         // Setup the listeners for the buttons
         for (int id : DIALER_KEYS) {
-            final View key = findViewById(id);
-            key.setOnClickListener(this);
-            key.setOnHoverListener(this);
+            final DialpadKeyButton key = (DialpadKeyButton) findViewById(id);
+            key.setOnPressedListener(this);
         }
 
         View view = findViewById(R.id.zero);
@@ -344,6 +345,30 @@
     @Override
     public void onClick(View view) {
         switch (view.getId()) {
+            case R.id.deleteButton: {
+                keyPressed(KeyEvent.KEYCODE_DEL);
+                return;
+            }
+            case R.id.floating_action_button: {
+                mHaptic.vibrate();  // Vibrate here too, just like we do for the regular keys
+                placeCall();
+                return;
+            }
+            case R.id.digits: {
+                if (mDigits.length() != 0) {
+                    mDigits.setCursorVisible(true);
+                }
+                return;
+            }
+        }
+    }
+
+    @Override
+    public void onPressed(View view, boolean pressed) {
+        if (!pressed) {
+            return;
+        }
+        switch (view.getId()) {
             case R.id.one: {
                 playTone(ToneGenerator.TONE_DTMF_1);
                 keyPressed(KeyEvent.KEYCODE_1);
@@ -404,59 +429,10 @@
                 keyPressed(KeyEvent.KEYCODE_STAR);
                 return;
             }
-            case R.id.deleteButton: {
-                keyPressed(KeyEvent.KEYCODE_DEL);
-                return;
-            }
-            case R.id.floating_action_button: {
-                mHaptic.vibrate();  // Vibrate here too, just like we do for the regular keys
-                placeCall();
-                return;
-            }
-            case R.id.digits: {
-                if (mDigits.length() != 0) {
-                    mDigits.setCursorVisible(true);
-                }
-                return;
-            }
         }
     }
 
     /**
-     * Implemented for {@link android.view.View.OnHoverListener}. Handles touch
-     * events for accessibility when touch exploration is enabled.
-     */
-    @Override
-    public boolean onHover(View v, MotionEvent event) {
-        // When touch exploration is turned on, lifting a finger while inside
-        // the button's hover target bounds should perform a click action.
-        if (mAccessibilityManager.isEnabled()
-                && mAccessibilityManager.isTouchExplorationEnabled()) {
-
-            switch (event.getActionMasked()) {
-                case MotionEvent.ACTION_HOVER_ENTER:
-                    // Lift-to-type temporarily disables double-tap activation.
-                    v.setClickable(false);
-                    break;
-                case MotionEvent.ACTION_HOVER_EXIT:
-                    final int left = v.getPaddingLeft();
-                    final int right = (v.getWidth() - v.getPaddingRight());
-                    final int top = v.getPaddingTop();
-                    final int bottom = (v.getHeight() - v.getPaddingBottom());
-                    final int x = (int) event.getX();
-                    final int y = (int) event.getY();
-                    if ((x > left) && (x < right) && (y > top) && (y < bottom)) {
-                        v.performClick();
-                    }
-                    v.setClickable(true);
-                    break;
-            }
-        }
-
-        return false;
-    }
-
-    /**
      * called for long touch events
      */
     @Override
diff --git a/src/com/android/phone/GsmUmtsOptions.java b/src/com/android/phone/GsmUmtsOptions.java
index 6791f27..8964cb5 100644
--- a/src/com/android/phone/GsmUmtsOptions.java
+++ b/src/com/android/phone/GsmUmtsOptions.java
@@ -16,12 +16,13 @@
 
 package com.android.phone;
 
+import android.content.Intent;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceScreen;
 import android.content.res.Resources;
 
-import com.android.internal.telephony.Phone;
+import android.provider.Settings;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.PhoneFactory;
 
@@ -49,6 +50,7 @@
     protected void create() {
         mPrefActivity.addPreferencesFromResource(R.xml.gsm_umts_options);
         mButtonAPNExpand = (PreferenceScreen) mPrefScreen.findPreference(BUTTON_APN_EXPAND_KEY);
+        boolean removedAPNExpand = false;
         mButtonOperatorSelectionExpand =
                 (PreferenceScreen) mPrefScreen.findPreference(BUTTON_OPERATOR_SELECTION_EXPAND_KEY);
         if (PhoneFactory.getDefaultPhone().getPhoneType() != PhoneConstants.PHONE_TYPE_GSM) {
@@ -62,9 +64,10 @@
             // Determine which options to display, for GSM these are defaulted
             // are defaulted to true in Phone/res/values/config.xml. But for
             // some operators like verizon they maybe overriden in operator
-            // specific resources or device specifc overlays.
-            if (!res.getBoolean(R.bool.config_apn_expand)) {
-                mPrefScreen.removePreference(mPrefScreen.findPreference(BUTTON_APN_EXPAND_KEY));
+            // specific resources or device specific overlays.
+            if (!res.getBoolean(R.bool.config_apn_expand) && mButtonAPNExpand != null) {
+                mPrefScreen.removePreference(mButtonAPNExpand);
+                removedAPNExpand = true;
             }
             if (!res.getBoolean(R.bool.config_operator_selection_expand)) {
                 mPrefScreen.removePreference(mPrefScreen
@@ -92,6 +95,22 @@
                 }
             }
         }
+        if (!removedAPNExpand) {
+            mButtonAPNExpand.setOnPreferenceClickListener(
+                    new Preference.OnPreferenceClickListener() {
+                        @Override
+                        public boolean onPreferenceClick(Preference preference) {
+                            // We need to build the Intent by hand as the Preference Framework
+                            // does not allow to add an Intent with some extras into a Preference
+                            // XML file
+                            final Intent intent = new Intent(Settings.ACTION_APN_SETTINGS);
+                            // This will setup the Home and Search affordance
+                            intent.putExtra(":settings:show_fragment_as_subsetting", true);
+                            mPrefActivity.startActivity(intent);
+                            return true;
+                        }
+            });
+        }
     }
 
     public boolean preferenceTreeClick(Preference preference) {
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index 637b429..89749ad 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -16,7 +16,6 @@
 
 package com.android.phone;
 
-import com.android.ims.ImsConfig;
 import com.android.ims.ImsManager;
 import com.android.ims.ImsException;
 import com.android.internal.telephony.Phone;
@@ -24,8 +23,6 @@
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.TelephonyProperties;
 
-import java.util.Map;
-
 import android.app.ActionBar;
 import android.app.AlertDialog;
 import android.content.Context;
@@ -41,10 +38,8 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.preference.CheckBoxPreference;
 import android.preference.ListPreference;
 import android.preference.Preference;
-import android.preference.Preference.OnPreferenceChangeListener;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceScreen;
 import android.preference.SwitchPreference;
@@ -199,13 +194,6 @@
         }
     }
 
-    public boolean isIMSOn() {
-        SharedPreferences imsPref =
-            getSharedPreferences(ImsManager.IMS_SHARED_PREFERENCES, Context.MODE_WORLD_READABLE);
-
-        return imsPref.getBoolean(ImsManager.KEY_IMS_ON, true);
-    }
-
     private void setIMS(boolean turnOn) {
         SharedPreferences imsPref =
             getSharedPreferences(ImsManager.IMS_SHARED_PREFERENCES, Context.MODE_WORLD_READABLE);
@@ -233,7 +221,7 @@
         mButton4glte = (SwitchPreference)findPreference(BUTTON_4G_LTE_KEY);
 
         mButton4glte.setOnPreferenceChangeListener(this);
-        mButton4glte.setChecked(isIMSOn());
+        mButton4glte.setChecked(ImsManager.isEnhanced4gLteModeSettingEnabledByUser(this));
 
         try {
             Context con = createPackageContext("com.android.systemui", 0);
@@ -350,6 +338,13 @@
                 prefSet.removePreference(pref);
             }
         }
+        Preference pref = prefSet.findPreference(BUTTON_4G_LTE_KEY);
+        if (pref != null) {
+            if (!ImsManager.isEnhanced4gLteModeSettingEnabledByPlatform(this)) {
+                ((SwitchPreference)pref).setChecked(false);
+                pref.setEnabled(false);
+            }
+        }
 
         ActionBar actionBar = getActionBar();
         if (actionBar != null) {
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index 39df173..6650892 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -341,7 +341,8 @@
                     .setContentTitle(notificationTitle)
                     .setContentText(notificationText)
                     .setContentIntent(pendingIntent)
-                    .setSound(ringtoneUri);
+                    .setSound(ringtoneUri)
+                    .setColor(mContext.getResources().getColor(R.color.dialer_theme_color));
             Notification notification = builder.getNotification();
 
             CallFeaturesSetting.migrateVoicemailVibrationSettingsIfNeeded(prefs);
@@ -428,6 +429,7 @@
         final Notification.Builder builder = new Notification.Builder(mContext);
         builder.setSmallIcon(android.R.drawable.stat_sys_warning);
         builder.setContentTitle(mContext.getText(R.string.roaming));
+        builder.setColor(mContext.getResources().getColor(R.color.dialer_theme_color));
         builder.setContentText(contentText);
         builder.setContentIntent(PendingIntent.getActivity(mContext, 0, intent, 0));
 
diff --git a/src/com/android/phone/Ringer.java b/src/com/android/phone/Ringer.java
index 668f8dc..b542ede 100644
--- a/src/com/android/phone/Ringer.java
+++ b/src/com/android/phone/Ringer.java
@@ -36,6 +36,8 @@
 import android.util.Log;
 
 import com.android.internal.telephony.Phone;
+import com.android.phone.common.util.SettingsUtil;
+
 /**
  * Ringer manager for the Phone app.
  */
@@ -210,7 +212,7 @@
     boolean shouldVibrate() {
         AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
         int ringerMode = audioManager.getRingerMode();
-        if (CallFeaturesSetting.getVibrateWhenRinging(mContext)) {
+        if (SettingsUtil.getVibrateWhenRingingSetting(mContext)) {
             return ringerMode != AudioManager.RINGER_MODE_SILENT;
         } else {
             return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
diff --git a/src/com/android/services/telephony/ConferenceConnection.java b/src/com/android/services/telephony/ConferenceConnection.java
deleted file mode 100644
index 33be0be..0000000
--- a/src/com/android/services/telephony/ConferenceConnection.java
+++ /dev/null
@@ -1,74 +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;
-
-import android.telecomm.Connection;
-import android.telephony.DisconnectCause;
-
-import com.android.internal.telephony.CallStateException;
-
-import java.util.List;
-
-/**
- * Manages state for a conference call.
- */
-final class ConferenceConnection extends Connection {
-    @Override
-    public void onChildrenChanged(List<Connection> children) {
-        if (children.isEmpty()) {
-            setDisconnected(DisconnectCause.LOCAL, "conference call disconnected.");
-            destroy();
-        }
-    }
-
-    /** ${inheritDoc} */
-    @Override
-    public void onDisconnect() {
-        // For conference-level disconnects, we need to make sure we disconnect the entire call,
-        // not just one of the connections. To do this, we go through the children and get a
-        // reference to the telephony-Call object and call hangup().
-        for (Connection connection : getChildConnections()) {
-            if (connection instanceof TelephonyConnection) {
-                com.android.internal.telephony.Connection origConnection =
-                        ((TelephonyConnection) connection).getOriginalConnection();
-                if (origConnection != null && origConnection.getCall() != null) {
-                    try {
-                        // getCall() returns what is the parent call of all conferenced conections
-                        // so we only need to call hangup on the main call object. Break once we've
-                        // done that.
-                        origConnection.getCall().hangup();
-                        break;
-                    } catch (CallStateException e) {
-                        Log.e(this, e, "Call state exception in conference hangup.");
-                    }
-                }
-            }
-        }
-    }
-
-    /** ${inheritDoc} */
-    @Override
-    public void onHold() {
-        for (Connection connection : getChildConnections()) {
-            if (connection instanceof TelephonyConnection) {
-                ((TelephonyConnection) connection).onHold();
-                // Hold only needs to be called on one of the children.
-                break;
-            }
-        }
-    }
-}
diff --git a/src/com/android/services/telephony/EmergencyCallHelper.java b/src/com/android/services/telephony/EmergencyCallHelper.java
index 5b3ebfc..c64a649 100644
--- a/src/com/android/services/telephony/EmergencyCallHelper.java
+++ b/src/com/android/services/telephony/EmergencyCallHelper.java
@@ -46,7 +46,7 @@
     }
 
     // Number of times to retry the call, and time between retry attempts.
-    public static final int MAX_NUM_RETRIES = 6;
+    public static final int MAX_NUM_RETRIES = 5;
     public static final long TIME_BETWEEN_RETRIES_MILLIS = 5000;  // msec
 
     // Handler message codes; see handleMessage()
@@ -180,9 +180,13 @@
     private boolean isOkToCall(int serviceState, PhoneConstants.State phoneState) {
         // Once we reach either STATE_IN_SERVICE or STATE_EMERGENCY_ONLY, it's finally OK to place
         // the emergency call.
-        return (phoneState == PhoneConstants.State.OFFHOOK)
+        return ((phoneState == PhoneConstants.State.OFFHOOK)
                 || (serviceState == ServiceState.STATE_IN_SERVICE)
-                || (serviceState == ServiceState.STATE_EMERGENCY_ONLY);
+                || (serviceState == ServiceState.STATE_EMERGENCY_ONLY)) ||
+
+                // Allow STATE_OUT_OF_SERVICE if we are at the max number of retries.
+                (mNumRetriesSoFar == MAX_NUM_RETRIES &&
+                 serviceState == ServiceState.STATE_OUT_OF_SERVICE);
     }
 
     /**
diff --git a/src/com/android/services/telephony/GsmConference.java b/src/com/android/services/telephony/GsmConference.java
new file mode 100644
index 0000000..d8bc11b
--- /dev/null
+++ b/src/com/android/services/telephony/GsmConference.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.services.telephony;
+
+import android.telecomm.PhoneCapabilities;
+import android.telecomm.Conference;
+import android.telecomm.Connection;
+import android.telecomm.PhoneAccountHandle;
+
+import com.android.internal.telephony.Call;
+import com.android.internal.telephony.CallStateException;
+
+import java.util.List;
+
+/**
+ * GSM-based conference call.
+ */
+public class GsmConference extends Conference {
+
+    public GsmConference(PhoneAccountHandle phoneAccount) {
+        super(phoneAccount);
+        setCapabilities(
+                PhoneCapabilities.SUPPORT_HOLD |
+                PhoneCapabilities.HOLD |
+                PhoneCapabilities.MUTE |
+                PhoneCapabilities.SWAP_CALLS);
+        setActive();
+    }
+
+    /**
+     * Invoked when the Conference and all it's {@link Connection}s should be disconnected.
+     */
+    @Override
+    public void onDisconnect() {
+        for (Connection connection : getConnections()) {
+            Call call = getMultipartyCallForConnection(connection, "onDisconnect");
+            if (call != null) {
+                try {
+                    call.hangup();
+                } catch (CallStateException e) {
+                    Log.e(this, e, "Exception thrown trying to hangup conference");
+                }
+            }
+        }
+    }
+
+    /**
+     * Invoked when the specified {@link Connection} should be separated from the conference call.
+     *
+     * @param connection The connection to separate.
+     */
+    @Override
+    public void onSeparate(Connection connection) {
+        com.android.internal.telephony.Connection radioConnection =
+                getOriginalConnection(connection, "onSeparate");
+        try {
+            radioConnection.separate();
+        } catch (CallStateException e) {
+            Log.e(this, e, "Exception thrown trying to separate a conference call");
+        }
+    }
+
+    /**
+     * Invoked when the conference should be put on hold.
+     */
+    @Override
+    public void onHold() {
+        List<Connection> connections = getConnections();
+        if (connections.isEmpty()) {
+            return;
+        }
+        ((GsmConnection) connections.get(0)).performHold();
+    }
+
+    /**
+     * Invoked when the conference should be moved from hold to active.
+     */
+    @Override
+    public void onUnhold() {
+        List<Connection> connections = getConnections();
+        if (connections.isEmpty()) {
+            return;
+        }
+        ((GsmConnection) connections.get(0)).performUnhold();
+    }
+
+    private Call getMultipartyCallForConnection(Connection connection, String tag) {
+        com.android.internal.telephony.Connection radioConnection =
+                getOriginalConnection(connection, tag);
+        if (radioConnection != null) {
+            Call call = radioConnection.getCall();
+            if (call != null && call.isMultiparty()) {
+                return call;
+            }
+        }
+        return null;
+    }
+
+    private com.android.internal.telephony.Connection getOriginalConnection(
+            Connection connection, String tag) {
+
+        if (connection instanceof GsmConnection) {
+            return ((GsmConnection) connection).getOriginalConnection();
+        } else {
+            Log.e(this, null, "Non GSM connection found in a Gsm conference (%s)", tag);
+            return null;
+        }
+    }
+}
diff --git a/src/com/android/services/telephony/GsmConferenceController.java b/src/com/android/services/telephony/GsmConferenceController.java
index a69d1e6..e3d0bf5 100644
--- a/src/com/android/services/telephony/GsmConferenceController.java
+++ b/src/com/android/services/telephony/GsmConferenceController.java
@@ -17,82 +17,61 @@
 package com.android.services.telephony;
 
 import java.util.ArrayList;
-
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
+import android.telecomm.Conference;
 import android.telecomm.Connection;
 
+import com.android.internal.telephony.Call;
+
 /**
  * Maintains a list of all the known GSM connections and implements GSM-specific conference
  * call functionality.
  */
 final class GsmConferenceController {
-    private static GsmConferenceController sInstance;
-
     private final Connection.Listener mConnectionListener = new Connection.Listener() {
                 @Override
                 public void onStateChanged(Connection c, int state) {
-                    // No need to recalculate for conference calls, just traditional calls.
-                    if (c != mGsmConferenceConnection) {
-                        recalculate();
-                    }
+                    recalculate();
                 }
 
                 /** ${inheritDoc} */
                 @Override
                 public void onDisconnected(Connection c, int cause, String message) {
-                    // When a connection disconnects, make sure to release its parent reference
-                    // so that the parent can move to disconnected as well.
-                    c.setParentConnection(null);
+                    recalculate();
                 }
             };
 
     /** The known GSM connections. */
     private final List<GsmConnection> mGsmConnections = new ArrayList<>();
 
+    private final TelephonyConnectionService mConnectionService;
+
+    public GsmConferenceController(TelephonyConnectionService connectionService) {
+        mConnectionService = connectionService;
+    }
+
     /** The GSM conference connection object. */
-    private ConferenceConnection mGsmConferenceConnection;
+    private Conference mGsmConference;
 
-    static void add(GsmConnection connection) {
-        if (sInstance == null) {
-            sInstance = new GsmConferenceController();
-        }
-        connection.addConnectionListener(sInstance.mConnectionListener);
-        sInstance.mGsmConnections.add(connection);
-        sInstance.recalculate();
+    void add(GsmConnection connection) {
+        mGsmConnections.add(connection);
+        connection.addConnectionListener(mConnectionListener);
+        recalculate();
     }
 
-    static void remove(GsmConnection connection) {
-        if (sInstance != null) {
-            connection.removeConnectionListener(sInstance.mConnectionListener);
-            sInstance.mGsmConnections.remove(connection);
-            sInstance.recalculate();
-
-            if (sInstance.mGsmConnections.size() == 0 &&
-                    sInstance.mGsmConferenceConnection == null) {
-                sInstance = null;
-            }
-        }
-    }
-
-    static ConferenceConnection createConferenceConnection(Connection rootConnection) {
-        if (sInstance != null) {
-            if (sInstance.mGsmConferenceConnection == null) {
-                sInstance.mGsmConferenceConnection = new ConferenceConnection();
-                Log.d(sInstance, "creating the conference connection: %s",
-                        sInstance.mGsmConferenceConnection);
-            }
-            if (rootConnection instanceof GsmConnection) {
-                ((GsmConnection) rootConnection).performConference();
-            }
-            return sInstance.mGsmConferenceConnection;
-        }
-        return null;
+    void remove(GsmConnection connection) {
+        connection.removeConnectionListener(mConnectionListener);
+        mGsmConnections.remove(connection);
+        recalculate();
     }
 
     private void recalculate() {
         recalculateConferenceable();
+        recalculateConference();
     }
 
     /**
@@ -141,5 +120,60 @@
         for (Connection connection : backgroundConnections) {
             connection.setConferenceableConnections(activeConnections);
         }
+        // TODO: Do not allow conferencing of already conferenced connections.
+    }
+
+    private void recalculateConference() {
+        Set<GsmConnection> conferencedConnections = new HashSet<>();
+
+        for (GsmConnection connection : mGsmConnections) {
+            com.android.internal.telephony.Connection radioConnection =
+                connection.getOriginalConnection();
+
+            if (radioConnection != null) {
+                Call.State state = radioConnection.getState();
+                Call call = radioConnection.getCall();
+                if ((state == Call.State.ACTIVE || state == Call.State.HOLDING) &&
+                        (call != null && call.isMultiparty())) {
+                    conferencedConnections.add(connection);
+                }
+            }
+        }
+
+        Log.d(this, "Recalculate conference calls %s %s.",
+                mGsmConference, conferencedConnections);
+
+        if (conferencedConnections.size() < 2) {
+            Log.d(this, "less than two conference calls!");
+            // No more connections are conferenced, destroy any existing conference.
+            if (mGsmConference != null) {
+                Log.d(this, "with a conference to destroy!");
+                mGsmConference.destroy();
+                mGsmConference = null;
+            }
+        } else {
+            if (mGsmConference != null) {
+                List<Connection> existingConnections = mGsmConference.getConnections();
+                // Remove any that no longer exist
+                for (Connection connection : existingConnections) {
+                    if (!conferencedConnections.contains(connection)) {
+                        mGsmConference.removeConnection(connection);
+                    }
+                }
+
+                // Add any new ones
+                for (Connection connection : conferencedConnections) {
+                    if (!existingConnections.contains(connection)) {
+                        mGsmConference.addConnection(connection);
+                    }
+                }
+            } else {
+                mGsmConference = new GsmConference(null);
+                for (Connection connection : conferencedConnections) {
+                    mGsmConference.addConnection(connection);
+                }
+                mConnectionService.addConference(mGsmConference);
+            }
+        }
     }
 }
diff --git a/src/com/android/services/telephony/GsmConnection.java b/src/com/android/services/telephony/GsmConnection.java
index 5140574..99f2cde 100644
--- a/src/com/android/services/telephony/GsmConnection.java
+++ b/src/com/android/services/telephony/GsmConnection.java
@@ -29,7 +29,6 @@
 
     GsmConnection(Connection connection) {
         super(connection);
-        GsmConferenceController.add(this);
     }
 
     /** {@inheritDoc} */
@@ -55,10 +54,16 @@
         }
     }
 
-    void performConference() {
+    @Override
+    public void performConference(TelephonyConnection otherConnection) {
         Log.d(this, "performConference - %s", this);
         if (getPhone() != null) {
             try {
+                // We dont use the "other" connection because there is no concept of that in the
+                // implementation of calls inside telephony. Basically, you can "conference" and it
+                // will conference with the background call.  We know that otherConnection is the
+                // background call because it would never have called setConferenceableConnections()
+                // otherwise.
                 getPhone().conference();
             } catch (CallStateException e) {
                 Log.e(this, e, "Failed to conference call.");
@@ -81,6 +86,5 @@
     @Override
     void onRemovedFromCallService() {
         super.onRemovedFromCallService();
-        GsmConferenceController.remove(this);
     }
 }
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 7ddb6d0..adb430c 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -31,7 +31,6 @@
 import com.android.internal.telephony.Phone;
 
 import java.lang.Override;
-import java.util.List;
 import java.util.Objects;
 
 /**
@@ -204,51 +203,12 @@
 
     @Override
     public void onHold() {
-        Log.v(this, "onHold");
-        // TODO: Can dialing calls be put on hold as well since they take up the
-        // foreground call slot?
-        if (Call.State.ACTIVE == mOriginalConnectionState) {
-            Log.v(this, "Holding active call");
-            try {
-                Phone phone = mOriginalConnection.getCall().getPhone();
-                Call ringingCall = phone.getRingingCall();
-
-                // Although the method says switchHoldingAndActive, it eventually calls a RIL method
-                // called switchWaitingOrHoldingAndActive. What this means is that if we try to put
-                // a call on hold while a call-waiting call exists, it'll end up accepting the
-                // call-waiting call, which is bad if that was not the user's intention. We are
-                // cheating here and simply skipping it because we know any attempt to hold a call
-                // while a call-waiting call is happening is likely a request from Telecomm prior to
-                // accepting the call-waiting call.
-                // TODO: Investigate a better solution. It would be great here if we
-                // could "fake" hold by silencing the audio and microphone streams for this call
-                // instead of actually putting it on hold.
-                if (ringingCall.getState() != Call.State.WAITING) {
-                    phone.switchHoldingAndActive();
-                }
-
-                // TODO: Cdma calls are slightly different.
-            } catch (CallStateException e) {
-                Log.e(this, e, "Exception occurred while trying to put call on hold.");
-            }
-        } else {
-            Log.w(this, "Cannot put a call that is not currently active on hold.");
-        }
+        performHold();
     }
 
     @Override
     public void onUnhold() {
-        Log.v(this, "onUnhold");
-        if (Call.State.HOLDING == mOriginalConnectionState) {
-            try {
-                // TODO: This doesn't handle multiple calls across connection services yet
-                mOriginalConnection.getCall().getPhone().switchHoldingAndActive();
-            } catch (CallStateException e) {
-                Log.e(this, e, "Exception occurred while trying to release call from hold.");
-            }
-        } else {
-            Log.w(this, "Cannot release a call that is not already on hold from hold.");
-        }
+        performUnhold();
     }
 
     @Override
@@ -288,15 +248,59 @@
     }
 
     @Override
-    public void onChildrenChanged(List<Connection> children) {
-        Log.v(this, "onChildrenChanged, children: " + children);
-    }
-
-    @Override
     public void onPhoneAccountClicked() {
         Log.v(this, "onPhoneAccountClicked");
     }
 
+    public void performHold() {
+        Log.v(this, "performHold");
+        // TODO: Can dialing calls be put on hold as well since they take up the
+        // foreground call slot?
+        if (Call.State.ACTIVE == mOriginalConnectionState) {
+            Log.v(this, "Holding active call");
+            try {
+                Phone phone = mOriginalConnection.getCall().getPhone();
+                Call ringingCall = phone.getRingingCall();
+
+                // Although the method says switchHoldingAndActive, it eventually calls a RIL method
+                // called switchWaitingOrHoldingAndActive. What this means is that if we try to put
+                // a call on hold while a call-waiting call exists, it'll end up accepting the
+                // call-waiting call, which is bad if that was not the user's intention. We are
+                // cheating here and simply skipping it because we know any attempt to hold a call
+                // while a call-waiting call is happening is likely a request from Telecomm prior to
+                // accepting the call-waiting call.
+                // TODO: Investigate a better solution. It would be great here if we
+                // could "fake" hold by silencing the audio and microphone streams for this call
+                // instead of actually putting it on hold.
+                if (ringingCall.getState() != Call.State.WAITING) {
+                    phone.switchHoldingAndActive();
+                }
+
+                // TODO: Cdma calls are slightly different.
+            } catch (CallStateException e) {
+                Log.e(this, e, "Exception occurred while trying to put call on hold.");
+            }
+        } else {
+            Log.w(this, "Cannot put a call that is not currently active on hold.");
+        }
+    }
+
+    public void performUnhold() {
+        Log.v(this, "performUnhold");
+        if (Call.State.HOLDING == mOriginalConnectionState) {
+            try {
+                // TODO: This doesn't handle multiple calls across connection services yet
+                mOriginalConnection.getCall().getPhone().switchHoldingAndActive();
+            } catch (CallStateException e) {
+                Log.e(this, e, "Exception occurred while trying to release call from hold.");
+            }
+        } else {
+            Log.w(this, "Cannot release a call that is not already on hold from hold.");
+        }
+    }
+
+    public void performConference(TelephonyConnection otherConnection) {}
+
     protected abstract int buildCallCapabilities();
 
     protected final void updateCallCapabilities() {
@@ -356,19 +360,15 @@
     private void hangup(int disconnectCause) {
         if (mOriginalConnection != null) {
             try {
-                Call call = mOriginalConnection.getCall();
-                if (call != null && !call.isMultiparty()) {
-                    call.hangup();
-                } else {
-                    mOriginalConnection.hangup();
-                }
-                // Set state deliberately since we are going to close() and will no longer be
-                // listening to state updates from mOriginalConnection
-                setDisconnected(disconnectCause, null);
+                mOriginalConnection.hangup();
             } catch (CallStateException e) {
                 Log.e(this, e, "Call to Connection.hangup failed with exception");
             }
         }
+
+        // Set state deliberately since we are going to close() and will no longer be
+        // listening to state updates from mOriginalConnection
+        setDisconnected(disconnectCause, null);
         close();
     }
 
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index bfae89e..7c4d1ae 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -47,6 +47,8 @@
 public class TelephonyConnectionService extends ConnectionService {
     static String SCHEME_TEL = "tel";
 
+    private final GsmConferenceController mGsmConferenceController =
+            new GsmConferenceController(this);
     private ComponentName mExpectedComponentName = null;
     private EmergencyCallHelper mEmergencyCallHelper;
 
@@ -93,8 +95,14 @@
                     "Phone is null");
         }
 
-        if (!isEmergencyNumber) {
-            int state = phone.getServiceState().getState();
+        int state = phone.getServiceState().getState();
+        boolean useEmergencyCallHelper = false;
+
+        if (isEmergencyNumber) {
+            if (state == ServiceState.STATE_POWER_OFF) {
+                useEmergencyCallHelper = true;
+            }
+        } else {
             switch (state) {
                 case ServiceState.STATE_IN_SERVICE:
                 case ServiceState.STATE_EMERGENCY_ONLY:
@@ -119,10 +127,9 @@
         }
         connection.setHandle(handle, PhoneConstants.PRESENTATION_ALLOWED);
         connection.setInitializing();
+        connection.setVideoState(request.getVideoState());
 
-        if (isEmergencyNumber) {
-            Log.d(this, "onCreateOutgoingConnection, doing startTurnOnRadioSequence for " +
-                    "emergency number");
+        if (useEmergencyCallHelper) {
             if (mEmergencyCallHelper == null) {
                 mEmergencyCallHelper = new EmergencyCallHelper(this);
             }
@@ -130,13 +137,16 @@
                     new EmergencyCallHelper.Callback() {
                         @Override
                         public void onComplete(boolean isRadioReady) {
-                            if (isRadioReady) {
+                            if (connection.getState() == Connection.STATE_DISCONNECTED) {
+                                // If the connection has already been disconnected, do nothing.
+                            } else if (isRadioReady) {
                                 connection.setInitialized();
                                 placeOutgoingConnection(connection, phone, request);
                             } else {
                                 Log.d(this, "onCreateOutgoingConnection, failed to turn on radio");
-                                connection.setFailed(DisconnectCause.POWER_OFF,
+                                connection.setDisconnected(DisconnectCause.POWER_OFF,
                                         "Failed to turn on radio.");
+                                connection.destroy();
                             }
                         }
                     });
@@ -149,20 +159,6 @@
     }
 
     @Override
-    public void onCreateConferenceConnection(
-            String token,
-            Connection connection,
-            Response<String, Connection> response) {
-        Log.v(this, "onCreateConferenceConnection, connection: " + connection);
-        if (connection instanceof GsmConnection || connection instanceof ConferenceConnection) {
-            if ((connection.getCallCapabilities() & PhoneCapabilities.MERGE_CALLS) != 0) {
-                response.onResult(token,
-                        GsmConferenceController.createConferenceConnection(connection));
-            }
-        }
-    }
-
-    @Override
     public Connection onCreateIncomingConnection(
             PhoneAccountHandle connectionManagerPhoneAccount,
             ConnectionRequest request) {
@@ -195,6 +191,30 @@
         }
     }
 
+    @Override
+    public void onConference(Connection connection1, Connection connection2) {
+        if (connection1 instanceof TelephonyConnection &&
+                connection2 instanceof TelephonyConnection) {
+            ((TelephonyConnection) connection1).performConference(
+                (TelephonyConnection) connection2);
+        }
+
+    }
+
+    @Override
+    public void onConnectionAdded(Connection connection) {
+        if (connection instanceof GsmConnection) {
+            mGsmConferenceController.add((GsmConnection) connection);
+        }
+    }
+
+    @Override
+    public void onConnectionRemoved(Connection connection) {
+        if (connection instanceof GsmConnection) {
+            mGsmConferenceController.remove((GsmConnection) connection);
+        }
+    }
+
     private void placeOutgoingConnection(
             TelephonyConnection connection, Phone phone, ConnectionRequest request) {
         String number = connection.getHandle().getSchemeSpecificPart();
@@ -204,7 +224,7 @@
             originalConnection = phone.dial(number, request.getVideoState());
         } catch (CallStateException e) {
             Log.e(this, e, "placeOutgoingConnection, phone.dial exception: " + e);
-            connection.setFailed(DisconnectCause.OUTGOING_FAILURE, e.getMessage());
+            connection.setDisconnected(DisconnectCause.OUTGOING_FAILURE, e.getMessage());
             return;
         }
 
@@ -221,7 +241,7 @@
                 startActivity(intent);
             }
             Log.d(this, "placeOutgoingConnection, phone.dial returned null");
-            connection.setFailed(disconnectCause, "Connection is null");
+            connection.setDisconnected(disconnectCause, "Connection is null");
         } else {
             connection.setOriginalConnection(originalConnection);
         }