am 297b563b: am 2f764cb9: Merge "ACTIVE->HOLD happens before HOLD->ACTIVE" into lmp-dev

* commit '297b563b9a6e3aa0db6d78afae169fc132bceef2':
  ACTIVE->HOLD happens before HOLD->ACTIVE
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 498b632..1383a62 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -191,7 +191,7 @@
         <item name="android:colorPrimaryDark">@color/network_operators_color_primary_dark</item>
     </style>
 
-    <style name="Empty" parent="@android:style/Theme.Holo">
+    <style name="Empty" parent="@android:style/Theme.Material.Light">
         <item name="android:windowIsTranslucent">true</item>
         <item name="android:windowBackground">@android:color/transparent</item>
         <item name="android:windowContentOverlay">@null</item>
@@ -227,16 +227,6 @@
         <item name="*android:taskOpenExitAnimation">@*android:anim/activity_open_exit</item>
     </style>
 
-    <!-- Theme for the InCallScreen activity.  This gives us a totally black
-         window background instead of the default dark grey.  (We don't just use
-         Theme.Black.NoTitleBar directly, since we want any popups or dialogs
-         from the InCallScreen to have the correct holo style. -->
-    <style name="Theme.InCallScreen" parent="@android:style/Theme.Holo.NoActionBar">
-        <item name="android:windowBackground">@android:color/black</item>
-
-        <item name="*android:windowAnimationStyle">@style/InCallAnimationStyle</item>
-    </style>
-
     <!-- Style for the call settings action bar.  Should be kept in sync with Dialer. -->
     <style name="DialtactsActionBarStyle" parent="@style/TelephonyActionBarStyle">
         <!-- Shift the title text to the right -->
diff --git a/res/xml/call_feature_setting.xml b/res/xml/call_feature_setting.xml
index e1bc216..6dedd1d 100644
--- a/res/xml/call_feature_setting.xml
+++ b/res/xml/call_feature_setting.xml
@@ -90,6 +90,12 @@
     </PreferenceScreen>
 
     <CheckBoxPreference
+        android:key="button_enable_video_calling"
+        android:title="@string/enable_video_calling_title"
+        android:persistent="true"
+        android:defaultValue="true" />
+
+    <CheckBoxPreference
         android:key="button_auto_retry_key"
         android:title="@string/auto_retry_mode_title"
         android:persistent="false"
diff --git a/sip/src/com/android/services/telephony/sip/SipEditor.java b/sip/src/com/android/services/telephony/sip/SipEditor.java
index 5a21fe8..ba06711 100644
--- a/sip/src/com/android/services/telephony/sip/SipEditor.java
+++ b/sip/src/com/android/services/telephony/sip/SipEditor.java
@@ -221,6 +221,10 @@
                 setRemovedProfileAndFinish();
                 return true;
             }
+            case android.R.id.home: {
+                finish();
+                return true;
+            }
         }
         return super.onOptionsItemSelected(item);
     }
diff --git a/src/com/android/phone/AccelerometerListener.java b/src/com/android/phone/AccelerometerListener.java
deleted file mode 100644
index 49d4a72..0000000
--- a/src/com/android/phone/AccelerometerListener.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2009 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.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-
-/**
- * This class is used to listen to the accelerometer to monitor the
- * orientation of the phone. The client of this class is notified when
- * the orientation changes between horizontal and vertical.
- */
-public final class AccelerometerListener {
-    private static final String TAG = "AccelerometerListener";
-    private static final boolean DEBUG = true;
-    private static final boolean VDEBUG = false;
-
-    private SensorManager mSensorManager;
-    private Sensor mSensor;
-
-    // mOrientation is the orientation value most recently reported to the client.
-    private int mOrientation;
-
-    // mPendingOrientation is the latest orientation computed based on the sensor value.
-    // This is sent to the client after a rebounce delay, at which point it is copied to
-    // mOrientation.
-    private int mPendingOrientation;
-
-    private OrientationListener mListener;
-
-    // Device orientation
-    public static final int ORIENTATION_UNKNOWN = 0;
-    public static final int ORIENTATION_VERTICAL = 1;
-    public static final int ORIENTATION_HORIZONTAL = 2;
-
-    private static final int ORIENTATION_CHANGED = 1234;
-
-    private static final int VERTICAL_DEBOUNCE = 100;
-    private static final int HORIZONTAL_DEBOUNCE = 500;
-    private static final double VERTICAL_ANGLE = 50.0;
-
-    public interface OrientationListener {
-        public void orientationChanged(int orientation);
-    }
-
-    public AccelerometerListener(Context context, OrientationListener listener) {
-        mListener = listener;
-        mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
-        mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
-    }
-
-    public void enable(boolean enable) {
-        if (DEBUG) Log.d(TAG, "enable(" + enable + ")");
-        synchronized (this) {
-            if (enable) {
-                mOrientation = ORIENTATION_UNKNOWN;
-                mPendingOrientation = ORIENTATION_UNKNOWN;
-                mSensorManager.registerListener(mSensorListener, mSensor,
-                        SensorManager.SENSOR_DELAY_NORMAL);
-            } else {
-                mSensorManager.unregisterListener(mSensorListener);
-                mHandler.removeMessages(ORIENTATION_CHANGED);
-            }
-        }
-    }
-
-    private void setOrientation(int orientation) {
-        synchronized (this) {
-            if (mPendingOrientation == orientation) {
-                // Pending orientation has not changed, so do nothing.
-                return;
-            }
-
-            // Cancel any pending messages.
-            // We will either start a new timer or cancel alltogether
-            // if the orientation has not changed.
-            mHandler.removeMessages(ORIENTATION_CHANGED);
-
-            if (mOrientation != orientation) {
-                // Set timer to send an event if the orientation has changed since its
-                // previously reported value.
-                mPendingOrientation = orientation;
-                Message m = mHandler.obtainMessage(ORIENTATION_CHANGED);
-                // set delay to our debounce timeout
-                int delay = (orientation == ORIENTATION_VERTICAL ? VERTICAL_DEBOUNCE
-                                                                 : HORIZONTAL_DEBOUNCE);
-                mHandler.sendMessageDelayed(m, delay);
-            } else {
-                // no message is pending
-                mPendingOrientation = ORIENTATION_UNKNOWN;
-            }
-        }
-    }
-
-    private void onSensorEvent(double x, double y, double z) {
-        if (VDEBUG) Log.d(TAG, "onSensorEvent(" + x + ", " + y + ", " + z + ")");
-
-        // If some values are exactly zero, then likely the sensor is not powered up yet.
-        // ignore these events to avoid false horizontal positives.
-        if (x == 0.0 || y == 0.0 || z == 0.0) return;
-
-        // magnitude of the acceleration vector projected onto XY plane
-        double xy = Math.sqrt(x*x + y*y);
-        // compute the vertical angle
-        double angle = Math.atan2(xy, z);
-        // convert to degrees
-        angle = angle * 180.0 / Math.PI;
-        int orientation = (angle >  VERTICAL_ANGLE ? ORIENTATION_VERTICAL : ORIENTATION_HORIZONTAL);
-        if (VDEBUG) Log.d(TAG, "angle: " + angle + " orientation: " + orientation);
-        setOrientation(orientation);
-    }
-
-    SensorEventListener mSensorListener = new SensorEventListener() {
-        public void onSensorChanged(SensorEvent event) {
-            onSensorEvent(event.values[0], event.values[1], event.values[2]);
-        }
-
-        public void onAccuracyChanged(Sensor sensor, int accuracy) {
-            // ignore
-        }
-    };
-
-    Handler mHandler = new Handler() {
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-            case ORIENTATION_CHANGED:
-                synchronized (this) {
-                    mOrientation = mPendingOrientation;
-                    if (DEBUG) {
-                        Log.d(TAG, "orientation: " +
-                            (mOrientation == ORIENTATION_HORIZONTAL ? "horizontal"
-                                : (mOrientation == ORIENTATION_VERTICAL ? "vertical"
-                                    : "unknown")));
-                    }
-                    mListener.orientationChanged(mOrientation);
-                }
-                break;
-            }
-        }
-    };
-}
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index c38df5c..e59f4fb 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -184,6 +184,8 @@
     private static final String PHONE_ACCOUNT_SETTINGS_KEY =
             "phone_account_settings_preference_screen";
 
+    private static final String ENABLE_VIDEO_CALLING_KEY = "button_enable_video_calling";
+
     private Intent mContactListIntent;
 
     /** Event for Async voicemail change call */
@@ -257,6 +259,7 @@
     private Preference mVoicemailNotificationRingtone;
     private CheckBoxPreference mVoicemailNotificationVibrate;
     private AccountSelectionPreference mDefaultOutgoingAccount;
+    private CheckBoxPreference mEnableVideoCalling;
 
     private class VoiceMailProvider {
         public VoiceMailProvider(String name, Intent intent) {
@@ -534,7 +537,7 @@
     @Override
     public boolean onPreferenceChange(Preference preference, Object objValue) {
         if (DBG) {
-            log("onPreferenceChange(). preferenece: \"" + preference + "\""
+            log("onPreferenceChange(). preference: \"" + preference + "\""
                     + ", value: \"" + objValue + "\"");
         }
 
@@ -577,6 +580,8 @@
                 mChangingVMorFwdDueToProviderChange = true;
                 saveVoiceMailAndForwardingNumber(newProviderKey, newProviderSettings);
             }
+        } else if (preference == mEnableVideoCalling) {
+            PhoneGlobals.getInstance().phoneMgr.enableVideoCalling((boolean) objValue);
         }
         // always let the preference setting proceed.
         return true;
@@ -1547,18 +1552,18 @@
 
         // get buttons
         PreferenceScreen prefSet = getPreferenceScreen();
-        mSubMenuVoicemailSettings = (EditPhoneNumberPreference)findPreference(BUTTON_VOICEMAIL_KEY);
-        if (mSubMenuVoicemailSettings != null) {
-            mSubMenuVoicemailSettings.setParentActivity(this, VOICEMAIL_PREF_ID, this);
-            mSubMenuVoicemailSettings.setDialogOnClosedListener(this);
-            mSubMenuVoicemailSettings.setDialogTitle(R.string.voicemail_settings_number_label);
-        }
+        mSubMenuVoicemailSettings = (EditPhoneNumberPreference) findPreference(BUTTON_VOICEMAIL_KEY);
+        mSubMenuVoicemailSettings.setParentActivity(this, VOICEMAIL_PREF_ID, this);
+        mSubMenuVoicemailSettings.setDialogOnClosedListener(this);
+        mSubMenuVoicemailSettings.setDialogTitle(R.string.voicemail_settings_number_label);
 
         mButtonDTMF = (ListPreference) findPreference(BUTTON_DTMF_KEY);
         mButtonAutoRetry = (CheckBoxPreference) findPreference(BUTTON_RETRY_KEY);
         mButtonHAC = (CheckBoxPreference) findPreference(BUTTON_HAC_KEY);
         mButtonTTY = (ListPreference) findPreference(BUTTON_TTY_KEY);
         mVoicemailProviders = (ListPreference) findPreference(BUTTON_VOICEMAIL_PROVIDER_KEY);
+        CheckBoxPreference mEnableVideoCalling =
+                (CheckBoxPreference) findPreference(ENABLE_VIDEO_CALLING_KEY);
 
         if (mVoicemailProviders != null) {
             mVoicemailProviders.setOnPreferenceChangeListener(this);
@@ -1573,42 +1578,46 @@
         }
 
 
-        if (mButtonDTMF != null) {
-            if (getResources().getBoolean(R.bool.dtmf_type_enabled)) {
-                mButtonDTMF.setOnPreferenceChangeListener(this);
-            } else {
-                prefSet.removePreference(mButtonDTMF);
-                mButtonDTMF = null;
-            }
+        if (getResources().getBoolean(R.bool.dtmf_type_enabled)) {
+            mButtonDTMF.setOnPreferenceChangeListener(this);
+            int dtmf = Settings.System.getInt(getContentResolver(),
+                    Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, Constants.DTMF_TONE_TYPE_NORMAL);
+            mButtonDTMF.setValueIndex(dtmf);
+        } else {
+            prefSet.removePreference(mButtonDTMF);
+            mButtonDTMF = null;
         }
 
-        if (mButtonAutoRetry != null) {
-            if (getResources().getBoolean(R.bool.auto_retry_enabled)) {
-                mButtonAutoRetry.setOnPreferenceChangeListener(this);
-            } else {
-                prefSet.removePreference(mButtonAutoRetry);
-                mButtonAutoRetry = null;
-            }
+        if (getResources().getBoolean(R.bool.auto_retry_enabled)) {
+            mButtonAutoRetry.setOnPreferenceChangeListener(this);
+            int autoretry = Settings.Global.getInt(
+                    getContentResolver(), Settings.Global.CALL_AUTO_RETRY, 0);
+            mButtonAutoRetry.setChecked(autoretry != 0);
+        } else {
+            prefSet.removePreference(mButtonAutoRetry);
+            mButtonAutoRetry = null;
         }
 
-        if (mButtonHAC != null) {
-            if (getResources().getBoolean(R.bool.hac_enabled)) {
-
-                mButtonHAC.setOnPreferenceChangeListener(this);
-            } else {
-                prefSet.removePreference(mButtonHAC);
-                mButtonHAC = null;
-            }
+        if (getResources().getBoolean(R.bool.hac_enabled)) {
+            mButtonHAC.setOnPreferenceChangeListener(this);
+            int hac = Settings.System.getInt(getContentResolver(), Settings.System.HEARING_AID, 0);
+            mButtonHAC.setChecked(hac != 0);
+        } else {
+            prefSet.removePreference(mButtonHAC);
+            mButtonHAC = null;
         }
 
-        if (mButtonTTY != null) {
-            TelecomManager telecomManager = TelecomManager.from(this);
-            if (telecomManager != null && telecomManager.isTtySupported()) {
-                mButtonTTY.setOnPreferenceChangeListener(this);
-            } else {
-                prefSet.removePreference(mButtonTTY);
-                mButtonTTY = null;
-            }
+        TelecomManager telecomManager = TelecomManager.from(this);
+        if (telecomManager != null && telecomManager.isTtySupported()) {
+            mButtonTTY.setOnPreferenceChangeListener(this);
+            int settingsTtyMode = Settings.Secure.getInt(getContentResolver(),
+                    Settings.Secure.PREFERRED_TTY_MODE,
+                    TelecomManager.TTY_MODE_OFF);
+            mButtonTTY.setValue(Integer.toString(settingsTtyMode));
+            updatePreferredTtyModeSummary(settingsTtyMode);
+        } else {
+            prefSet.removePreference(mButtonTTY);
+            mButtonTTY = null;
         }
 
         if (!getResources().getBoolean(R.bool.world_phone)) {
@@ -1661,31 +1670,6 @@
         updateVoiceNumberField();
         mVMProviderSettingsForced = false;
 
-        if (mButtonDTMF != null) {
-            int dtmf = Settings.System.getInt(getContentResolver(),
-                    Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, Constants.DTMF_TONE_TYPE_NORMAL);
-            mButtonDTMF.setValueIndex(dtmf);
-        }
-
-        if (mButtonAutoRetry != null) {
-            int autoretry = Settings.Global.getInt(getContentResolver(),
-                    Settings.Global.CALL_AUTO_RETRY, 0);
-            mButtonAutoRetry.setChecked(autoretry != 0);
-        }
-
-        if (mButtonHAC != null) {
-            int hac = Settings.System.getInt(getContentResolver(), Settings.System.HEARING_AID, 0);
-            mButtonHAC.setChecked(hac != 0);
-        }
-
-        if (mButtonTTY != null) {
-            int settingsTtyMode = Settings.Secure.getInt(getContentResolver(),
-                    Settings.Secure.PREFERRED_TTY_MODE,
-                    TelecomManager.TTY_MODE_OFF);
-            mButtonTTY.setValue(Integer.toString(settingsTtyMode));
-            updatePreferredTtyModeSummary(settingsTtyMode);
-        }
-
         SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
                 mPhone.getContext());
         if (migrateVoicemailVibrationSettingsIfNeeded(prefs)) {
@@ -1693,6 +1677,11 @@
                     BUTTON_VOICEMAIL_NOTIFICATION_VIBRATE_KEY, false));
         }
 
+        mEnableVideoCalling.setChecked(PhoneGlobals.getInstance().phoneMgr.isVideoCallingEnabled());
+        mEnableVideoCalling.setOnPreferenceChangeListener(this);
+        // TODO: Perform checks to determine whether we should remove the preference.
+        prefSet.removePreference(mEnableVideoCalling);
+
         // Look up the voicemail ringtone name asynchronously and update its preference.
         new Thread(mVoicemailRingtoneLookupRunnable).start();
     }
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index a8de874..eb74956 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -524,14 +524,12 @@
             intent.setData(Uri.fromParts(PhoneAccount.SCHEME_TEL, mLastNumber, null));
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             startActivity(intent);
-            finish();
         } else {
             if (DBG) Log.d(LOG_TAG, "rejecting bad requested number " + mLastNumber);
 
-            // erase the number and throw up an alert dialog.
-            mDigits.getText().delete(0, mDigits.getText().length());
             showDialog(BAD_EMERGENCY_NUMBER_DIALOG);
         }
+        mDigits.getText().delete(0, mDigits.getText().length());
     }
 
     /**
diff --git a/src/com/android/phone/INetworkQueryService.aidl b/src/com/android/phone/INetworkQueryService.aidl
index 749163c..0733d73 100644
--- a/src/com/android/phone/INetworkQueryService.aidl
+++ b/src/com/android/phone/INetworkQueryService.aidl
@@ -34,12 +34,21 @@
      * that will be sent upon query completion.
      */
     void startNetworkQuery(in INetworkQueryServiceCallback cb);
- 
+
     /**
      * Tells the service that the requested query is to be ignored.
-     * This may not do anything for the Query request in the 
+     * This may not do anything for the Query request in the
      * underlying RIL, but it ensures that the callback is removed
      * from the list of notifications.
      */
     void stopNetworkQuery(in INetworkQueryServiceCallback cb);
+
+    /**
+     * Tells the service to unregister the network query callback.
+     * Will not attempt to stop an ongoing network query.
+     * Functionally may be the same as stopNetworkQuery since that
+     * function also does not stop a query request in the underlying
+     * RIL.
+     */
+    void unregisterCallback(in INetworkQueryServiceCallback cb);
 }
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index 20134ba..07c9d73 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -196,10 +196,10 @@
     }
 
     private void setIMS(boolean turnOn) {
-        SharedPreferences imsPref =
-            getSharedPreferences(ImsManager.IMS_SHARED_PREFERENCES, Context.MODE_WORLD_READABLE);
-
-        imsPref.edit().putBoolean(ImsManager.KEY_IMS_ON, turnOn).commit();
+        int value = (turnOn) ? 1:0;
+        android.provider.Settings.Global.putInt(
+                  mPhone.getContext().getContentResolver(),
+                  android.provider.Settings.Global.VOLTE_VT_ENABLED, value);
     }
 
     @Override
diff --git a/src/com/android/phone/NetworkQueryService.java b/src/com/android/phone/NetworkQueryService.java
index be8c78e..77f3720 100644
--- a/src/com/android/phone/NetworkQueryService.java
+++ b/src/com/android/phone/NetworkQueryService.java
@@ -34,20 +34,20 @@
 
 /**
  * Service code used to assist in querying the network for service
- * availability.   
+ * availability.
  */
 public class NetworkQueryService extends Service {
     // debug data
     private static final String LOG_TAG = "NetworkQuery";
-    private static final boolean DBG = false;
+    private static final boolean DBG = true;
 
     // static events
-    private static final int EVENT_NETWORK_SCAN_COMPLETED = 100; 
-    
-    // static states indicating the query status of the service 
+    private static final int EVENT_NETWORK_SCAN_COMPLETED = 100;
+
+    // static states indicating the query status of the service
     private static final int QUERY_READY = -1;
     private static final int QUERY_IS_RUNNING = -2;
-    
+
     // error statuses that will be retured in the callback.
     public static final int QUERY_OK = 0;
     public static final int QUERY_EXCEPTION = 1;
@@ -142,24 +142,31 @@
             // currently we just unregister the callback, since there is 
             // no way to tell the RIL to terminate the query request.  
             // This means that the RIL may still be busy after the stop 
-            // request was made, but the state tracking logic ensures 
-            // that the delay will only last for 1 request even with 
-            // repeated button presses in the NetworkSetting activity. 
+            // request was made, but the state tracking logic ensures
+            // that the delay will only last for 1 request even with
+            // repeated button presses in the NetworkSetting activity.
+            unregisterCallback(cb);
+        }
+
+        /**
+         * Unregisters the callback without impacting an underlying query.
+         */
+        public void unregisterCallback(INetworkQueryServiceCallback cb) {
             if (cb != null) {
                 synchronized (mCallbacks) {
                     if (DBG) log("unregistering callback " + cb.getClass().toString());
                     mCallbacks.unregister(cb);
                 }
-            }            
+            }
         }
     };
-    
+
     @Override
     public void onCreate() {
         mState = QUERY_READY;
         mPhone = PhoneFactory.getDefaultPhone();
     }
-    
+
     /**
      * Required for service implementation.
      */
diff --git a/src/com/android/phone/NetworkSetting.java b/src/com/android/phone/NetworkSetting.java
index 4bd02cf..5925b0f 100644
--- a/src/com/android/phone/NetworkSetting.java
+++ b/src/com/android/phone/NetworkSetting.java
@@ -51,7 +51,7 @@
         implements DialogInterface.OnCancelListener {
 
     private static final String LOG_TAG = "phone";
-    private static final boolean DBG = false;
+    private static final boolean DBG = true;
 
     private static final int EVENT_NETWORK_SCAN_COMPLETED = 100;
     private static final int EVENT_NETWORK_SELECTION_DONE = 200;
@@ -106,6 +106,10 @@
                         if (DBG) log("manual network selection: succeeded!");
                         displayNetworkSelectionSucceeded();
                     }
+
+                    // update the phone in case replaced as part of selection
+                    mPhone = PhoneGlobals.getPhone();
+
                     break;
                 case EVENT_AUTO_SELECT_DONE:
                     if (DBG) log("hideProgressPanel");
@@ -118,7 +122,7 @@
                         // "auto select" is always trigged in foreground, so "auto select" dialog
                         //  should be shown when "auto select" is trigged. Should NOT get
                         // this exception, and Log it.
-                        Log.w(LOG_TAG, "[NetworksList] Fail to dismiss auto select dialog", e);
+                        Log.w(LOG_TAG, "[NetworksList] Fail to dismiss auto select dialog ", e);
                     }
                     getPreferenceScreen().setEnabled(true);
 
@@ -130,6 +134,10 @@
                         if (DBG) log("automatic network selection: succeeded!");
                         displayNetworkSelectionSucceeded();
                     }
+
+                    // update the phone in case replaced as part of selection
+                    mPhone = PhoneGlobals.getPhone();
+
                     break;
             }
 
@@ -212,7 +220,7 @@
         try {
             mNetworkQueryService.stopNetworkQuery(mCallback);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            log("onCancel: exception from stopNetworkQuery " + e);
         }
         finish();
     }
@@ -274,6 +282,13 @@
      */
     @Override
     protected void onDestroy() {
+        try {
+            // used to un-register callback
+            mNetworkQueryService.unregisterCallback(mCallback);
+        } catch (RemoteException e) {
+            log("onDestroy: exception from unregisterCallback " + e);
+        }
+
         if (!mUnavailable) {
             // unbind the service.
             unbindService(mNetworkQueryServiceConnection);
@@ -389,6 +404,14 @@
         try {
             mNetworkQueryService.startNetworkQuery(mCallback);
         } catch (RemoteException e) {
+            log("loadNetworksList: exception from startNetworkQuery " + e);
+            if (mIsForeground) {
+                try {
+                    dismissDialog(DIALOG_NETWORK_LIST_LOAD);
+                } catch (IllegalArgumentException e1) {
+                    // do nothing
+                }
+            }
         }
 
         displayEmptyNetworkList(false);
@@ -404,10 +427,16 @@
     private void networksListLoaded(List<OperatorInfo> result, int status) {
         if (DBG) log("networks list loaded");
 
+        // used to un-register callback
+        try {
+            mNetworkQueryService.unregisterCallback(mCallback);
+        } catch (RemoteException e) {
+            log("networksListLoaded: exception from unregisterCallback " + e);
+        }
+
         // update the state of the preferences.
         if (DBG) log("hideProgressPanel");
 
-
         // Always try to dismiss the dialog because activity may
         // be moved to background after dialog is shown.
         try {
@@ -416,7 +445,7 @@
             // It's not a error in following scenario, we just ignore it.
             // "Load list" dialog will not show, if NetworkQueryService is
             // connected after this activity is moved to background.
-            if (DBG) log("Fail to dismiss network load list dialog");
+            if (DBG) log("Fail to dismiss network load list dialog " + e);
         }
 
         getPreferenceScreen().setEnabled(true);
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index f9a0989..ffbdebf 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -136,11 +136,12 @@
     AppOpsManager mAppOps;
     MainThreadHandler mMainThreadHandler;
 
-    SharedPreferences carrierPrivilegeConfigs;
+    SharedPreferences mTelephonySharedPreferences;
     private static final String PREF_CARRIERS_ALPHATAG_PREFIX = "carrier_alphtag_";
     private static final String PREF_CARRIERS_NUMBER_PREFIX = "carrier_number_";
     private static final String PREF_CARRIERS_SIMPLIFIED_NETWORK_SETTINGS_PREFIX =
             "carrier_simplified_network_settings_";
+    private static final String PREF_ENABLE_VIDEO_CALLING = "enable_video_calling";
 
     /**
      * A request object to use for transmitting data to an ICC.
@@ -703,7 +704,7 @@
         mCM = PhoneGlobals.getInstance().mCM;
         mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
         mMainThreadHandler = new MainThreadHandler();
-        carrierPrivilegeConfigs =
+        mTelephonySharedPreferences =
                 PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
         publish();
     }
@@ -1947,7 +1948,7 @@
         String iccId = getIccId(subId);
         if (iccId != null) {
             String snsPrefKey = PREF_CARRIERS_SIMPLIFIED_NETWORK_SETTINGS_PREFIX + iccId;
-            SharedPreferences.Editor editor = carrierPrivilegeConfigs.edit();
+            SharedPreferences.Editor editor = mTelephonySharedPreferences.edit();
             if (enable) {
                 editor.putBoolean(snsPrefKey, true);
             } else {
@@ -1963,7 +1964,7 @@
         String iccId = getIccId(subId);
         if (iccId != null) {
             String snsPrefKey = PREF_CARRIERS_SIMPLIFIED_NETWORK_SETTINGS_PREFIX + iccId;
-            return carrierPrivilegeConfigs.getBoolean(snsPrefKey, false);
+            return mTelephonySharedPreferences.getBoolean(snsPrefKey, false);
         }
         return false;
     }
@@ -1975,7 +1976,7 @@
         String iccId = getIccId(subId);
         if (iccId != null) {
             String alphaTagPrefKey = PREF_CARRIERS_ALPHATAG_PREFIX + iccId;
-            SharedPreferences.Editor editor = carrierPrivilegeConfigs.edit();
+            SharedPreferences.Editor editor = mTelephonySharedPreferences.edit();
             if (alphaTag == null) {
                 editor.remove(alphaTagPrefKey);
             } else {
@@ -1999,7 +2000,7 @@
         String iccId = getIccId(subId);
         if (iccId != null) {
             String numberPrefKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
-            return carrierPrivilegeConfigs.getString(numberPrefKey, null);
+            return mTelephonySharedPreferences.getString(numberPrefKey, null);
         }
         return null;
     }
@@ -2011,7 +2012,7 @@
         String iccId = getIccId(subId);
         if (iccId != null) {
             String alphaTagPrefKey = PREF_CARRIERS_ALPHATAG_PREFIX + iccId;
-            return carrierPrivilegeConfigs.getString(alphaTagPrefKey, null);
+            return mTelephonySharedPreferences.getString(alphaTagPrefKey, null);
         }
         return null;
     }
@@ -2067,4 +2068,18 @@
     public int getRadioAccessFamily(int phoneId) {
         return ProxyController.getInstance().getRadioAccessFamily(phoneId);
     }
+
+    @Override
+    public void enableVideoCalling(boolean enable) {
+        enforceModifyPermission();
+        SharedPreferences.Editor editor = mTelephonySharedPreferences.edit();
+        editor.putBoolean(PREF_ENABLE_VIDEO_CALLING, enable);
+        editor.commit();
+    }
+
+    @Override
+    public boolean isVideoCallingEnabled() {
+        enforceReadPermission();
+        return mTelephonySharedPreferences.getBoolean(PREF_ENABLE_VIDEO_CALLING, true);
+    }
 }
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index 56d26c9..b3d64db 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -117,6 +117,13 @@
     /** Noise suppression status as selected by user */
     private static boolean sIsNoiseSuppressionEnabled = true;
 
+    /**
+     * Theme to use for dialogs displayed by utility methods in this class. This is needed
+     * because these dialogs are displayed using the application context, which does not resolve
+     * the dialog theme correctly.
+     */
+    private static final int THEME = AlertDialog.THEME_DEVICE_DEFAULT_LIGHT;
+
     private static class FgRingCalls {
         private Call fgCall;
         private Call ringing;
@@ -955,7 +962,7 @@
                 // places the message at the forefront of the UI.
 
                 if (sUssdDialog == null) {
-                    sUssdDialog = new AlertDialog.Builder(context)
+                    sUssdDialog = new AlertDialog.Builder(context, THEME)
                             .setPositiveButton(R.string.ok, null)
                             .setCancelable(true)
                             .setOnDismissListener(new DialogInterface.OnDismissListener() {
@@ -1045,7 +1052,7 @@
                     };
 
                 // build the dialog
-                final AlertDialog newDialog = new AlertDialog.Builder(context)
+                final AlertDialog newDialog = new AlertDialog.Builder(context, THEME)
                         .setMessage(text)
                         .setView(dialogView)
                         .setPositiveButton(R.string.send_button, mUSSDDialogListener)
diff --git a/src/com/android/phone/Ringer.java b/src/com/android/phone/Ringer.java
deleted file mode 100644
index b542ede..0000000
--- a/src/com/android/phone/Ringer.java
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Copyright (C) 2006 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.media.AudioAttributes;
-import android.media.AudioManager;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.IPowerManager;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.SystemVibrator;
-import android.os.Vibrator;
-import android.provider.Settings;
-import android.util.Log;
-
-import com.android.internal.telephony.Phone;
-import com.android.phone.common.util.SettingsUtil;
-
-/**
- * Ringer manager for the Phone app.
- */
-public class Ringer {
-    private static final String LOG_TAG = "Ringer";
-    private static final boolean DBG =
-            (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
-
-    private static final int PLAY_RING_ONCE = 1;
-    private static final int STOP_RING = 3;
-
-    private static final int VIBRATE_LENGTH = 1000; // ms
-    private static final int PAUSE_LENGTH = 1000; // ms
-
-    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
-            .build();
-
-    /** The singleton instance. */
-    private static Ringer sInstance;
-
-    // Uri for the ringtone.
-    Uri mCustomRingtoneUri = Settings.System.DEFAULT_RINGTONE_URI;
-
-    private final BluetoothManager mBluetoothManager;
-    Ringtone mRingtone;
-    Vibrator mVibrator;
-    IPowerManager mPowerManager;
-    volatile boolean mContinueVibrating;
-    VibratorThread mVibratorThread;
-    Context mContext;
-    private Worker mRingThread;
-    private Handler mRingHandler;
-    private long mFirstRingEventTime = -1;
-    private long mFirstRingStartTime = -1;
-
-    /**
-     * Initialize the singleton Ringer instance.
-     * This is only done once, at startup, from PhoneApp.onCreate().
-     */
-    /* package */ static Ringer init(Context context, BluetoothManager bluetoothManager) {
-        synchronized (Ringer.class) {
-            if (sInstance == null) {
-                sInstance = new Ringer(context, bluetoothManager);
-            } else {
-                Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);
-            }
-            return sInstance;
-        }
-    }
-
-    /** Private constructor; @see init() */
-    private Ringer(Context context, BluetoothManager bluetoothManager) {
-        mContext = context;
-        mBluetoothManager = bluetoothManager;
-        mPowerManager = IPowerManager.Stub.asInterface(
-                ServiceManager.getService(Context.POWER_SERVICE));
-        // We don't rely on getSystemService(Context.VIBRATOR_SERVICE) to make sure this
-        // vibrator object will be isolated from others.
-        mVibrator = new SystemVibrator(context);
-    }
-
-    /**
-     * After a radio technology change, e.g. from CDMA to GSM or vice versa,
-     * the Context of the Ringer has to be updated. This is done by that function.
-     *
-     * @parameter Phone, the new active phone for the appropriate radio
-     * technology
-     */
-    void updateRingerContextAfterRadioTechnologyChange(Phone phone) {
-        if(DBG) Log.d(LOG_TAG, "updateRingerContextAfterRadioTechnologyChange...");
-        mContext = phone.getContext();
-    }
-
-    /**
-     * @return true if we're playing a ringtone and/or vibrating
-     *     to indicate that there's an incoming call.
-     *     ("Ringing" here is used in the general sense.  If you literally
-     *     need to know if we're playing a ringtone or vibrating, use
-     *     isRingtonePlaying() or isVibrating() instead.)
-     *
-     * @see isVibrating
-     * @see isRingtonePlaying
-     */
-    boolean isRinging() {
-        synchronized (this) {
-            return (isRingtonePlaying() || isVibrating());
-        }
-    }
-
-    /**
-     * @return true if the ringtone is playing
-     * @see isVibrating
-     * @see isRinging
-     */
-    private boolean isRingtonePlaying() {
-        synchronized (this) {
-            return (mRingtone != null && mRingtone.isPlaying()) ||
-                    (mRingHandler != null && mRingHandler.hasMessages(PLAY_RING_ONCE));
-        }
-    }
-
-    /**
-     * @return true if we're vibrating in response to an incoming call
-     * @see isVibrating
-     * @see isRinging
-     */
-    private boolean isVibrating() {
-        synchronized (this) {
-            return (mVibratorThread != null);
-        }
-    }
-
-    /**
-     * Starts the ringtone and/or vibrator
-     */
-    void ring() {
-        if (DBG) log("ring()...");
-
-        synchronized (this) {
-            try {
-                if (mBluetoothManager.showBluetoothIndication()) {
-                    mPowerManager.setAttentionLight(true, 0x000000ff);
-                } else {
-                    mPowerManager.setAttentionLight(true, 0x00ffffff);
-                }
-            } catch (RemoteException ex) {
-                // the other end of this binder call is in the system process.
-            }
-
-            if (shouldVibrate() && mVibratorThread == null) {
-                mContinueVibrating = true;
-                mVibratorThread = new VibratorThread();
-                if (DBG) log("- starting vibrator...");
-                mVibratorThread.start();
-            }
-            AudioManager audioManager =
-                    (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-
-            if (audioManager.getStreamVolume(AudioManager.STREAM_RING) == 0) {
-                if (DBG) log("skipping ring because volume is zero");
-                return;
-            }
-
-            makeLooper();
-            if (mFirstRingEventTime < 0) {
-                mFirstRingEventTime = SystemClock.elapsedRealtime();
-                mRingHandler.sendEmptyMessage(PLAY_RING_ONCE);
-            } else {
-                // For repeat rings, figure out by how much to delay
-                // the ring so that it happens the correct amount of
-                // time after the previous ring
-                if (mFirstRingStartTime > 0) {
-                    // Delay subsequent rings by the delta between event
-                    // and play time of the first ring
-                    if (DBG) {
-                        log("delaying ring by " + (mFirstRingStartTime - mFirstRingEventTime));
-                    }
-                    mRingHandler.sendEmptyMessageDelayed(PLAY_RING_ONCE,
-                            mFirstRingStartTime - mFirstRingEventTime);
-                } else {
-                    // We've gotten two ring events so far, but the ring
-                    // still hasn't started. Reset the event time to the
-                    // time of this event to maintain correct spacing.
-                    mFirstRingEventTime = SystemClock.elapsedRealtime();
-                }
-            }
-        }
-    }
-
-    boolean shouldVibrate() {
-        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-        int ringerMode = audioManager.getRingerMode();
-        if (SettingsUtil.getVibrateWhenRingingSetting(mContext)) {
-            return ringerMode != AudioManager.RINGER_MODE_SILENT;
-        } else {
-            return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
-        }
-    }
-
-    /**
-     * Stops the ringtone and/or vibrator if any of these are actually
-     * ringing/vibrating.
-     */
-    void stopRing() {
-        synchronized (this) {
-            if (DBG) log("stopRing()...");
-
-            try {
-                mPowerManager.setAttentionLight(false, 0x00000000);
-            } catch (RemoteException ex) {
-                // the other end of this binder call is in the system process.
-            }
-
-            if (mRingHandler != null) {
-                mRingHandler.removeCallbacksAndMessages(null);
-                Message msg = mRingHandler.obtainMessage(STOP_RING);
-                msg.obj = mRingtone;
-                mRingHandler.sendMessage(msg);
-                PhoneUtils.setAudioMode();
-                mRingThread = null;
-                mRingHandler = null;
-                mRingtone = null;
-                mFirstRingEventTime = -1;
-                mFirstRingStartTime = -1;
-            } else {
-                if (DBG) log("- stopRing: null mRingHandler!");
-            }
-
-            if (mVibratorThread != null) {
-                if (DBG) log("- stopRing: cleaning up vibrator thread...");
-                mContinueVibrating = false;
-                mVibratorThread = null;
-            }
-            // Also immediately cancel any vibration in progress.
-            mVibrator.cancel();
-        }
-    }
-
-    private class VibratorThread extends Thread {
-        public void run() {
-            while (mContinueVibrating) {
-                mVibrator.vibrate(VIBRATE_LENGTH, VIBRATION_ATTRIBUTES);
-                SystemClock.sleep(VIBRATE_LENGTH + PAUSE_LENGTH);
-            }
-        }
-    }
-    private class Worker implements Runnable {
-        private final Object mLock = new Object();
-        private Looper mLooper;
-
-        Worker(String name) {
-            Thread t = new Thread(null, this, name);
-            t.start();
-            synchronized (mLock) {
-                while (mLooper == null) {
-                    try {
-                        mLock.wait();
-                    } catch (InterruptedException ex) {
-                    }
-                }
-            }
-        }
-
-        public Looper getLooper() {
-            return mLooper;
-        }
-
-        public void run() {
-            synchronized (mLock) {
-                Looper.prepare();
-                mLooper = Looper.myLooper();
-                mLock.notifyAll();
-            }
-            Looper.loop();
-        }
-
-        public void quit() {
-            mLooper.quit();
-        }
-    }
-
-    /**
-     * Sets the ringtone uri in preparation for ringtone creation
-     * in makeLooper().  This uri is defaulted to the phone-wide
-     * default ringtone.
-     */
-    void setCustomRingtoneUri (Uri uri) {
-        if (uri != null) {
-            mCustomRingtoneUri = uri;
-        }
-    }
-
-    private void makeLooper() {
-        if (mRingThread == null) {
-            mRingThread = new Worker("ringer");
-            mRingHandler = new Handler(mRingThread.getLooper()) {
-                @Override
-                public void handleMessage(Message msg) {
-                    Ringtone r = null;
-                    switch (msg.what) {
-                        case PLAY_RING_ONCE:
-                            if (DBG) log("mRingHandler: PLAY_RING_ONCE...");
-                            if (mRingtone == null && !hasMessages(STOP_RING)) {
-                                // create the ringtone with the uri
-                                if (DBG) log("creating ringtone: " + mCustomRingtoneUri);
-                                r = RingtoneManager.getRingtone(mContext, mCustomRingtoneUri);
-                                synchronized (Ringer.this) {
-                                    if (!hasMessages(STOP_RING)) {
-                                        mRingtone = r;
-                                    }
-                                }
-                            }
-                            r = mRingtone;
-                            if (r != null && !hasMessages(STOP_RING) && !r.isPlaying()) {
-                                PhoneUtils.setAudioMode();
-                                r.play();
-                                synchronized (Ringer.this) {
-                                    if (mFirstRingStartTime < 0) {
-                                        mFirstRingStartTime = SystemClock.elapsedRealtime();
-                                    }
-                                }
-                            }
-                            break;
-                        case STOP_RING:
-                            if (DBG) log("mRingHandler: STOP_RING...");
-                            r = (Ringtone) msg.obj;
-                            if (r != null) {
-                                r.stop();
-                            } else {
-                                if (DBG) log("- STOP_RING with null ringtone!  msg = " + msg);
-                            }
-                            getLooper().quit();
-                            break;
-                    }
-                }
-            };
-        }
-    }
-
-    private static void log(String msg) {
-        Log.d(LOG_TAG, msg);
-    }
-}
diff --git a/src/com/android/phone/SmallerHitTargetTouchListener.java b/src/com/android/phone/SmallerHitTargetTouchListener.java
deleted file mode 100644
index 8e1bf16..0000000
--- a/src/com/android/phone/SmallerHitTargetTouchListener.java
+++ /dev/null
@@ -1,115 +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.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-
-/**
- * OnTouchListener used to shrink the "hit target" of some onscreen buttons.
- *
- * We do this for a few specific buttons which are vulnerable to
- * "false touches" because either (1) they're near the edge of the
- * screen and might be unintentionally touched while holding the
- * device in your hand, (2) they're in the upper corners and might
- * be touched by the user's ear before the prox sensor has a chance to
- * kick in, or (3) they are close to other buttons.
- */
-public class SmallerHitTargetTouchListener implements View.OnTouchListener {
-    private static final String TAG = "SmallerHitTargetTouchListener";
-
-    /**
-     * Edge dimensions where a touch does not register an action (in DIP).
-     */
-    private static final int HIT_TARGET_EDGE_IGNORE_DP_X = 30;
-    private static final int HIT_TARGET_EDGE_IGNORE_DP_Y = 10;
-    private static final int HIT_TARGET_MIN_SIZE_DP_X = HIT_TARGET_EDGE_IGNORE_DP_X * 3;
-    private static final int HIT_TARGET_MIN_SIZE_DP_Y = HIT_TARGET_EDGE_IGNORE_DP_Y * 3;
-
-    // True if the most recent DOWN event was a "hit".
-    boolean mDownEventHit;
-
-    /**
-     * Called when a touch event is dispatched to a view. This allows listeners to
-     * get a chance to respond before the target view.
-     *
-     * @return True if the listener has consumed the event, false otherwise.
-     *         (In other words, we return true when the touch is *outside*
-     *         the "smaller hit target", which will prevent the actual
-     *         button from handling these events.)
-     */
-    @Override
-    public boolean onTouch(View v, MotionEvent event) {
-        // if (DBG) log("SmallerHitTargetTouchListener: " + v + ", event " + event);
-
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            // Note that event.getX() and event.getY() are already
-            // translated into the View's coordinates.  (In other words,
-            // "0,0" is a touch on the upper-left-most corner of the view.)
-            final int touchX = (int) event.getX();
-            final int touchY = (int) event.getY();
-
-            final int viewWidth = v.getWidth();
-            final int viewHeight = v.getHeight();
-
-            final float pixelDensity = v.getResources().getDisplayMetrics().density;
-            final int targetMinSizeX = (int) (HIT_TARGET_MIN_SIZE_DP_X * pixelDensity);
-            final int targetMinSizeY = (int) (HIT_TARGET_MIN_SIZE_DP_Y * pixelDensity);
-
-            int edgeIgnoreX = (int) (HIT_TARGET_EDGE_IGNORE_DP_X * pixelDensity);
-            int edgeIgnoreY = (int) (HIT_TARGET_EDGE_IGNORE_DP_Y * pixelDensity);
-
-            // If we are dealing with smaller buttons where the dead zone defined by
-            // HIT_TARGET_EDGE_IGNORE_DP_[X|Y] is too large.
-            if (viewWidth < targetMinSizeX || viewHeight < targetMinSizeY) {
-                // This really should not happen given our two use cases (as of this writing)
-                // in the call edge button and secondary calling card. However, we leave
-                // this is as a precautionary measure.
-                Log.w(TAG, "onTouch: view is too small for SmallerHitTargetTouchListener");
-                edgeIgnoreX = 0;
-                edgeIgnoreY = 0;
-            }
-
-            final int minTouchX = edgeIgnoreX;
-            final int maxTouchX = viewWidth - edgeIgnoreX;
-            final int minTouchY = edgeIgnoreY;
-            final int maxTouchY = viewHeight - edgeIgnoreY;
-
-            if (touchX < minTouchX || touchX > maxTouchX ||
-                    touchY < minTouchY || touchY > maxTouchY) {
-                // Missed!
-                // if (DBG) log("  -> MISSED!");
-                mDownEventHit = false;
-                return true;  // Consume this event; don't let the button see it
-            } else {
-                // Hit!
-                // if (DBG) log("  -> HIT!");
-                mDownEventHit = true;
-                return false;  // Let this event through to the actual button
-            }
-        } else {
-            // This is a MOVE, UP or CANCEL event.
-            //
-            // We only do the "smaller hit target" check on DOWN events.
-            // For the subsequent MOVE/UP/CANCEL events, we let them
-            // through to the actual button IFF the previous DOWN event
-            // got through to the actual button (i.e. it was a "hit".)
-            return !mDownEventHit;
-        }
-    }
-}
diff --git a/src/com/android/phone/TelephonyDebugService.java b/src/com/android/phone/TelephonyDebugService.java
index fdfe8f5..8503574 100644
--- a/src/com/android/phone/TelephonyDebugService.java
+++ b/src/com/android/phone/TelephonyDebugService.java
@@ -47,6 +47,8 @@
 
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
+                                       "Requires DUMP");
         mDebugService.dump(fd, pw, args);
     }
 }
diff --git a/src/com/android/phone/TimeConsumingPreferenceActivity.java b/src/com/android/phone/TimeConsumingPreferenceActivity.java
index 19c4dda..bab9469 100644
--- a/src/com/android/phone/TimeConsumingPreferenceActivity.java
+++ b/src/com/android/phone/TimeConsumingPreferenceActivity.java
@@ -101,7 +101,7 @@
                 default:
                     msgId = R.string.exception_error;
                     // The error is not recoverable on dialog exit.
-                    builder.setPositiveButton(R.string.close_dialog, mDismissAndFinish);
+                    builder.setPositiveButton(R.string.close_dialog, mDismiss);
                     break;
             }
 
diff --git a/src/com/android/services/telephony/CdmaConnection.java b/src/com/android/services/telephony/CdmaConnection.java
index 1915fe0..779cb70 100644
--- a/src/com/android/services/telephony/CdmaConnection.java
+++ b/src/com/android/services/telephony/CdmaConnection.java
@@ -156,9 +156,12 @@
 
     @Override
     protected int buildCallCapabilities() {
-        int capabilities = 0;
+        int capabilities = super.buildCallCapabilities();
         if (mAllowMute) {
-            capabilities = PhoneCapabilities.MUTE;
+            capabilities |= PhoneCapabilities.MUTE;
+        }
+        if (getConference() == null) {
+            capabilities |= PhoneCapabilities.ADD_CALL;
         }
         return capabilities;
     }
@@ -205,6 +208,10 @@
      * Read the settings to determine which type of DTMF method this CDMA phone calls.
      */
     private boolean useBurstDtmf() {
+        if (isImsConnection()) {
+            Log.d(this,"in ims call, return false");
+            return false;
+        }
         int dtmfTypeSetting = Settings.System.getInt(
                 getPhone().getContext().getContentResolver(),
                 Settings.System.DTMF_TONE_TYPE_WHEN_DIALING,
diff --git a/src/com/android/services/telephony/GsmConnection.java b/src/com/android/services/telephony/GsmConnection.java
index 479d247..1632457 100644
--- a/src/com/android/services/telephony/GsmConnection.java
+++ b/src/com/android/services/telephony/GsmConnection.java
@@ -64,7 +64,10 @@
 
     @Override
     protected int buildCallCapabilities() {
-        int capabilities = PhoneCapabilities.MUTE | PhoneCapabilities.SUPPORT_HOLD;
+        int capabilities = super.buildCallCapabilities();
+        capabilities |= PhoneCapabilities.ADD_CALL;
+        capabilities |= PhoneCapabilities.MUTE;
+        capabilities |= PhoneCapabilities.SUPPORT_HOLD;
         if (getState() == STATE_ACTIVE || getState() == STATE_HOLDING) {
             capabilities |= PhoneCapabilities.HOLD;
         }
diff --git a/src/com/android/services/telephony/GsmConference.java b/src/com/android/services/telephony/TelephonyConference.java
similarity index 82%
rename from src/com/android/services/telephony/GsmConference.java
rename to src/com/android/services/telephony/TelephonyConference.java
index 44abc77..fdb7261 100644
--- a/src/com/android/services/telephony/GsmConference.java
+++ b/src/com/android/services/telephony/TelephonyConference.java
@@ -28,13 +28,15 @@
 import java.util.List;
 
 /**
- * GSM-based conference call.
+ * TelephonyConnection-based conference call for GSM conferences and IMS conferences (which may
+ * be either GSM-based or CDMA-based).
  */
-public class GsmConference extends Conference {
+public class TelephonyConference extends Conference {
 
-    public GsmConference(PhoneAccountHandle phoneAccount) {
+    public TelephonyConference(PhoneAccountHandle phoneAccount) {
         super(phoneAccount);
         setCapabilities(
+                PhoneCapabilities.ADD_CALL |
                 PhoneCapabilities.SUPPORT_HOLD |
                 PhoneCapabilities.HOLD |
                 PhoneCapabilities.MUTE |
@@ -94,7 +96,7 @@
      */
     @Override
     public void onHold() {
-        final GsmConnection connection = getFirstConnection();
+        final TelephonyConnection connection = getFirstConnection();
         if (connection != null) {
             connection.performHold();
         }
@@ -105,7 +107,7 @@
      */
     @Override
     public void onUnhold() {
-        final GsmConnection connection = getFirstConnection();
+        final TelephonyConnection connection = getFirstConnection();
         if (connection != null) {
             connection.performUnhold();
         }
@@ -113,7 +115,7 @@
 
     @Override
     public void onPlayDtmfTone(char c) {
-        final GsmConnection connection = getFirstConnection();
+        final TelephonyConnection connection = getFirstConnection();
         if (connection != null) {
             connection.onPlayDtmfTone(c);
         }
@@ -121,7 +123,7 @@
 
     @Override
     public void onStopDtmfTone() {
-        final GsmConnection connection = getFirstConnection();
+        final TelephonyConnection connection = getFirstConnection();
         if (connection != null) {
             connection.onStopDtmfTone();
         }
@@ -142,19 +144,19 @@
     private com.android.internal.telephony.Connection getOriginalConnection(
             Connection connection, String tag) {
 
-        if (connection instanceof GsmConnection) {
-            return ((GsmConnection) connection).getOriginalConnection();
+        if (connection instanceof TelephonyConnection) {
+            return ((TelephonyConnection) connection).getOriginalConnection();
         } else {
-            Log.e(this, null, "Non GSM connection found in a Gsm conference (%s)", tag);
+            Log.e(this, null, "Non TelephonyConnection found in a TelephonyConference (%s)", tag);
             return null;
         }
     }
 
-    private GsmConnection getFirstConnection() {
+    private TelephonyConnection getFirstConnection() {
         final List<Connection> connections = getConnections();
         if (connections.isEmpty()) {
             return null;
         }
-        return (GsmConnection) connections.get(0);
+        return (TelephonyConnection) connections.get(0);
     }
 }
diff --git a/src/com/android/services/telephony/GsmConferenceController.java b/src/com/android/services/telephony/TelephonyConferenceController.java
similarity index 67%
rename from src/com/android/services/telephony/GsmConferenceController.java
rename to src/com/android/services/telephony/TelephonyConferenceController.java
index b6aaaf9..5786b25 100644
--- a/src/com/android/services/telephony/GsmConferenceController.java
+++ b/src/com/android/services/telephony/TelephonyConferenceController.java
@@ -29,11 +29,13 @@
 import com.android.internal.telephony.Call;
 
 /**
- * Maintains a list of all the known GSM connections and implements GSM-specific conference
- * call functionality.
+ * Maintains a list of all the known TelephonyConnections connections and controls GSM and
+ * default IMS conference call behavior. This functionality is characterized by the support of
+ * two top-level calls, in contrast to a CDMA conference call which automatically starts a
+ * conference when there are two calls.
  */
-final class GsmConferenceController {
-    private static final int GSM_CONFERENCE_MAX_SIZE = 5;
+final class TelephonyConferenceController {
+    private static final int TELEPHONY_CONFERENCE_MAX_SIZE = 5;
 
     private final Connection.Listener mConnectionListener = new Connection.Listener() {
         @Override
@@ -49,31 +51,31 @@
 
         @Override
         public void onDestroyed(Connection connection) {
-            remove((GsmConnection) connection);
+            remove((TelephonyConnection) connection);
         }
     };
 
-    /** The known GSM connections. */
-    private final List<GsmConnection> mGsmConnections = new ArrayList<>();
+    /** The known connections. */
+    private final List<TelephonyConnection> mTelephonyConnections = new ArrayList<>();
 
     private final TelephonyConnectionService mConnectionService;
 
-    public GsmConferenceController(TelephonyConnectionService connectionService) {
+    public TelephonyConferenceController(TelephonyConnectionService connectionService) {
         mConnectionService = connectionService;
     }
 
-    /** The GSM conference connection object. */
-    private Conference mGsmConference;
+    /** The TelephonyConference connection object. */
+    private TelephonyConference mTelephonyConference;
 
-    void add(GsmConnection connection) {
-        mGsmConnections.add(connection);
+    void add(TelephonyConnection connection) {
+        mTelephonyConnections.add(connection);
         connection.addConnectionListener(mConnectionListener);
         recalculate();
     }
 
-    void remove(GsmConnection connection) {
+    void remove(TelephonyConnection connection) {
         connection.removeConnectionListener(mConnectionListener);
-        mGsmConnections.remove(connection);
+        mTelephonyConnections.remove(connection);
         recalculate();
     }
 
@@ -83,7 +85,7 @@
     }
 
     private boolean isFullConference(Conference conference) {
-        return conference.getConnections().size() >= GSM_CONFERENCE_MAX_SIZE;
+        return conference.getConnections().size() >= TELEPHONY_CONFERENCE_MAX_SIZE;
     }
 
     private boolean participatesInFullConference(Connection connection) {
@@ -95,13 +97,13 @@
      * Calculates the conference-capable state of all GSM connections in this connection service.
      */
     private void recalculateConferenceable() {
-        Log.v(this, "recalculateConferenceable : %d", mGsmConnections.size());
+        Log.v(this, "recalculateConferenceable : %d", mTelephonyConnections.size());
 
-        List<Connection> activeConnections = new ArrayList<>(mGsmConnections.size());
-        List<Connection> backgroundConnections = new ArrayList<>(mGsmConnections.size());
+        List<Connection> activeConnections = new ArrayList<>(mTelephonyConnections.size());
+        List<Connection> backgroundConnections = new ArrayList<>(mTelephonyConnections.size());
 
         // Loop through and collect all calls which are active or holding
-        for (GsmConnection connection : mGsmConnections) {
+        for (Connection connection : mTelephonyConnections) {
             Log.d(this, "recalc - %s %s", connection.getState(), connection);
 
             if (!participatesInFullConference(connection)) {
@@ -136,23 +138,24 @@
         }
 
         // Set the conference as conferenceable with all the connections
-        if (mGsmConference != null && !isFullConference(mGsmConference)) {
-            List<Connection> nonConferencedConnections = new ArrayList<>(mGsmConnections.size());
-            for (GsmConnection c : mGsmConnections) {
+        if (mTelephonyConference != null && !isFullConference(mTelephonyConference)) {
+            List<Connection> nonConferencedConnections =
+                    new ArrayList<>(mTelephonyConnections.size());
+            for (TelephonyConnection c : mTelephonyConnections) {
                 if (c.getConference() == null) {
                     nonConferencedConnections.add(c);
                 }
             }
-            mGsmConference.setConferenceableConnections(nonConferencedConnections);
+            mTelephonyConference.setConferenceableConnections(nonConferencedConnections);
         }
 
         // TODO: Do not allow conferencing of already conferenced connections.
     }
 
     private void recalculateConference() {
-        Set<GsmConnection> conferencedConnections = new HashSet<>();
+        Set<TelephonyConnection> conferencedConnections = new HashSet<>();
 
-        for (GsmConnection connection : mGsmConnections) {
+        for (TelephonyConnection connection : mTelephonyConnections) {
             com.android.internal.telephony.Connection radioConnection =
                 connection.getOriginalConnection();
 
@@ -167,50 +170,50 @@
         }
 
         Log.d(this, "Recalculate conference calls %s %s.",
-                mGsmConference, conferencedConnections);
+                mTelephonyConference, 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) {
+            if (mTelephonyConference != null) {
                 Log.d(this, "with a conference to destroy!");
-                mGsmConference.destroy();
-                mGsmConference = null;
+                mTelephonyConference.destroy();
+                mTelephonyConference = null;
             }
         } else {
-            if (mGsmConference != null) {
-                List<Connection> existingConnections = mGsmConference.getConnections();
+            if (mTelephonyConference != null) {
+                List<Connection> existingConnections = mTelephonyConference.getConnections();
                 // Remove any that no longer exist
                 for (Connection connection : existingConnections) {
                     if (!conferencedConnections.contains(connection)) {
-                        mGsmConference.removeConnection(connection);
+                        mTelephonyConference.removeConnection(connection);
                     }
                 }
 
                 // Add any new ones
                 for (Connection connection : conferencedConnections) {
                     if (!existingConnections.contains(connection)) {
-                        mGsmConference.addConnection(connection);
+                        mTelephonyConference.addConnection(connection);
                     }
                 }
             } else {
-                mGsmConference = new GsmConference(null);
+                mTelephonyConference = new TelephonyConference(null);
                 for (Connection connection : conferencedConnections) {
                     Log.d(this, "Adding a connection to a conference call: %s %s",
-                            mGsmConference, connection);
-                    mGsmConference.addConnection(connection);
+                            mTelephonyConference, connection);
+                    mTelephonyConference.addConnection(connection);
                 }
-                mConnectionService.addConference(mGsmConference);
+                mConnectionService.addConference(mTelephonyConference);
             }
 
             // Set the conference state to the same state as its child connections.
-            Connection conferencedConnection = mGsmConference.getConnections().get(0);
+            Connection conferencedConnection = mTelephonyConference.getConnections().get(0);
             switch (conferencedConnection.getState()) {
                 case Connection.STATE_ACTIVE:
-                    mGsmConference.setActive();
+                    mTelephonyConference.setActive();
                     break;
                 case Connection.STATE_HOLDING:
-                    mGsmConference.setOnHold();
+                    mTelephonyConference.setOnHold();
                     break;
             }
         }
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 53d9681..b8d3142 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -21,6 +21,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.telecom.AudioState;
+import android.telecom.Conference;
 import android.telecom.Connection;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneCapabilities;
@@ -144,6 +145,8 @@
     private com.android.internal.telephony.Connection mOriginalConnection;
     private Call.State mOriginalConnectionState = Call.State.IDLE;
 
+    private boolean mWasImsConnection;
+
     /**
      * Determines if the {@link TelephonyConnection} has local video capabilities.
      * This is used when {@link TelephonyConnection#updateCallCapabilities()}} is called,
@@ -257,6 +260,25 @@
         }
     }
 
+    @Override
+    public void onConferenceChanged() {
+        Conference conference = getConference();
+        if (conference == null) {
+            return;
+        }
+
+        // If the conference was an IMS connection currently or before, disable MANAGE_CONFERENCE
+        // as the default behavior. If there is a conference event package, this may be overridden.
+        if (mWasImsConnection) {
+            int capabilities = conference.getCapabilities();
+            if (PhoneCapabilities.can(capabilities, PhoneCapabilities.MANAGE_CONFERENCE)) {
+                int newCapabilities =
+                        PhoneCapabilities.remove(capabilities, PhoneCapabilities.MANAGE_CONFERENCE);
+                conference.setCapabilities(newCapabilities);
+            }
+        }
+    }
+
     public void performHold() {
         Log.v(this, "performHold");
         // TODO: Can dialing calls be put on hold as well since they take up the
@@ -324,7 +346,21 @@
 
     public void performConference(TelephonyConnection otherConnection) {}
 
-    protected abstract int buildCallCapabilities();
+    /**
+     * Builds call capabilities common to all TelephonyConnections. Namely, apply IMS-based
+     * capabilities.
+     */
+    protected int buildCallCapabilities() {
+        int callCapabilities = 0;
+        if (isImsConnection()) {
+            callCapabilities |= PhoneCapabilities.ADD_CALL;
+            callCapabilities |= PhoneCapabilities.SUPPORT_HOLD;
+            if (getState() == STATE_ACTIVE || getState() == STATE_HOLDING) {
+                callCapabilities |= PhoneCapabilities.HOLD;
+            }
+        }
+        return callCapabilities;
+    }
 
     protected final void updateCallCapabilities() {
         int newCallCapabilities = buildCallCapabilities();
@@ -387,6 +423,10 @@
         setVideoProvider(mOriginalConnection.getVideoProvider());
         setAudioQuality(mOriginalConnection.getAudioQuality());
 
+        if (isImsConnection()) {
+            mWasImsConnection = true;
+        }
+
         updateAddress();
     }
 
@@ -617,12 +657,11 @@
     private int applyConferenceTerminationCapabilities(int callCapabilities) {
         int currentCapabilities = callCapabilities;
 
-        // An IMS call cannot be individually disconnected or separated from its parent conference
-        boolean isImsCall = getOriginalConnection() instanceof ImsPhoneConnection;
-        if (!isImsCall) {
-            currentCapabilities |=
-                    PhoneCapabilities.DISCONNECT_FROM_CONFERENCE
-                    | PhoneCapabilities.SEPARATE_FROM_CONFERENCE;
+        // An IMS call cannot be individually disconnected or separated from its parent conference.
+        // If the call was IMS, even if it hands over to GMS, these capabilities are not supported.
+        if (!mWasImsConnection) {
+            currentCapabilities |= PhoneCapabilities.DISCONNECT_FROM_CONFERENCE;
+            currentCapabilities |= PhoneCapabilities.SEPARATE_FROM_CONFERENCE;
         }
 
         return currentCapabilities;
@@ -702,6 +741,15 @@
         return false;
     }
 
+    /**
+     * Whether the original connection is an IMS connection.
+     * @return {@code True} if the original connection is an IMS connection, {@code false}
+     *     otherwise.
+     */
+    protected boolean isImsConnection() {
+        return getOriginalConnection() instanceof ImsPhoneConnection;
+    }
+
     private static Uri getAddressFromNumber(String number) {
         // Address can be null for blocked calls.
         if (number == null) {
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 73a57d3..9d309dc 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -48,8 +48,8 @@
  * Service for making GSM and CDMA connections.
  */
 public class TelephonyConnectionService extends ConnectionService {
-    private final GsmConferenceController mGsmConferenceController =
-            new GsmConferenceController(this);
+    private final TelephonyConferenceController mTelephonyConferenceController =
+            new TelephonyConferenceController(this);
     private final CdmaConferenceController mCdmaConferenceController =
             new CdmaConferenceController(this);
     private ComponentName mExpectedComponentName = null;
@@ -348,13 +348,17 @@
         int phoneType = phone.getPhoneType();
         if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
             GsmConnection connection = new GsmConnection(originalConnection);
-            mGsmConferenceController.add(connection);
+            mTelephonyConferenceController.add(connection);
             return connection;
         } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
             boolean allowMute = allowMute(phone);
             CdmaConnection connection = new CdmaConnection(
                     originalConnection, mEmergencyTonePlayer, allowMute, isOutgoing);
-            mCdmaConferenceController.add(connection);
+            if (connection.isImsConnection()) {
+                mTelephonyConferenceController.add(connection);
+            } else {
+                mCdmaConferenceController.add(connection);
+            }
             return connection;
         } else {
             return null;
diff --git a/src/com/android/services/telephony/TtyManager.java b/src/com/android/services/telephony/TtyManager.java
index f3f11f4..6c8a495 100644
--- a/src/com/android/services/telephony/TtyManager.java
+++ b/src/com/android/services/telephony/TtyManager.java
@@ -34,6 +34,7 @@
     private final TtyBroadcastReceiver mReceiver = new TtyBroadcastReceiver();
     private final Phone mPhone;
     private int mTtyMode;
+    private int mUiTtyMode = -1;
 
     private final Handler mHandler = new Handler() {
         @Override
@@ -73,6 +74,7 @@
 
         IntentFilter intentFilter = new IntentFilter(
                 TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);
+        intentFilter.addAction(TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED);
         context.registerReceiver(mReceiver, intentFilter);
 
         int ttyMode = TelecomManager.TTY_MODE_OFF;
@@ -81,6 +83,7 @@
             ttyMode = telecomManager.getCurrentTtyMode();
         }
         updateTtyMode(ttyMode);
+        updateUiTtyMode(ttyMode);
     }
 
     private void updateTtyMode(int ttyMode) {
@@ -90,6 +93,16 @@
                 mHandler.obtainMessage(MSG_SET_TTY_MODE_RESPONSE));
     }
 
+    private void updateUiTtyMode(int ttyMode) {
+        Log.i(this, "updateUiTtyMode %d -> %d", mUiTtyMode, ttyMode);
+        if(mUiTtyMode != ttyMode) {
+            mUiTtyMode = ttyMode;
+            mPhone.setUiTTYMode(telecomModeToPhoneMode(ttyMode), null);
+        } else {
+           Log.i(this, "ui tty mode didnt change");
+        }
+    }
+
     private final class TtyBroadcastReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -99,6 +112,10 @@
                 int ttyMode = intent.getIntExtra(
                         TelecomManager.EXTRA_CURRENT_TTY_MODE, TelecomManager.TTY_MODE_OFF);
                 updateTtyMode(ttyMode);
+            } else if (action.equals(TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED)) {
+                int newPreferredTtyMode = intent.getIntExtra(
+                        TelecomManager.EXTRA_TTY_PREFERRED_MODE, TelecomManager.TTY_MODE_OFF);
+                updateUiTtyMode(newPreferredTtyMode);
             }
         }
     }