Merge "Correct grammar for "unable to merge" error message."
diff --git a/res/values/config.xml b/res/values/config.xml
index 855fa92..5ad369f 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -137,7 +137,7 @@
     <!-- DEPRECATED: Use CarrierConfigManager#KEY_PREFER_2G_BOOL -->
     <bool name="config_prefer_2g" translatable="false">true</bool>
     <!-- Show enabled lte option for lte device -->
-    <bool name="config_enabled_lte" translatable="false">false</bool>
+    <bool name="config_enabled_lte" translatable="false">true</bool>
     <!-- Show enabled tdscdma option for device -->
     <bool name="config_support_tdscdma" translatable="false">false</bool>
     <!-- Show enabled tdscdma option for device when connect roaming network -->
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 9068c13..7fe534c 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1804,4 +1804,17 @@
     <!-- Message displayed to the user to indicate that a held call has been released /
          disconnected. -->
     <string name="supp_service_held_call_released">Held call has been released.</string>
+
+    <!-- In-call screen: error message shown when the user has attempted to place a new outgoing
+         call, but there is already a call in dialing state. -->
+    <string name="callFailed_already_dialing">Cannot place a call as another outgoing call is already dialing.</string>
+    <!-- In-call screen: error message shown when the user has attempted to place a new outgoing
+         call while there is already a call in ringing state. -->
+    <string name="callFailed_already_ringing">Cannot place a call as there is an unanswered incoming call.  Answer or reject the incoming call prior to placing a new call.</string>
+    <!-- In-call screen: error message shown when the user attempts to place a call, but calling has
+         been disabled using a debug property. -->
+    <string name="callFailed_calling_disabled">Cannot place a call as calling has been disabled using the ro.telephony.disable-call system property.</string>
+    <!-- In-call screen: error message shown when the user attempts to place a call, but calling has
+         been disabled using a debug property. -->
+    <string name="callFailed_too_many_calls">Cannot place a call a there are already two calls in progress.  Disconnect one of the calls or merge them into a conference prior to placing a new call.</string>
 </resources>
diff --git a/src/com/android/phone/GsmUmtsOptions.java b/src/com/android/phone/GsmUmtsOptions.java
index a3f5cfb..35aab34 100644
--- a/src/com/android/phone/GsmUmtsOptions.java
+++ b/src/com/android/phone/GsmUmtsOptions.java
@@ -28,7 +28,6 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.settingslib.RestrictedLockUtils;
 
@@ -54,7 +53,7 @@
     private PreferenceScreen mPrefScreen;
 
     public GsmUmtsOptions(PreferenceFragment prefFragment, PreferenceScreen prefScreen,
-            final int subId, INetworkQueryService queryService) {
+            final int subId) {
         final Context context = prefFragment.getContext();
         mPrefFragment = prefFragment;
         mPrefScreen = prefScreen;
@@ -68,19 +67,17 @@
 
         mNetworkOperator.initialize();
 
-        update(subId, queryService);
+        update(subId);
     }
 
-    // Unlike mPrefFragment or mPrefScreen, subId or queryService may change during lifecycle of
-    // GsmUmtsOptions. When that happens, we update GsmUmtsOptions with new parameters.
-    protected void update(final int subId, INetworkQueryService queryService) {
+    // Unlike mPrefFragment or mPrefScreen, subId  may change during lifecycle of GsmUmtsOptions.
+    // When that happens, we update GsmUmtsOptions with new parameters.
+    protected void update(final int subId) {
         boolean addAPNExpand = true;
         boolean addNetworkOperatorsCategory = true;
         boolean addCarrierSettings = true;
         final TelephonyManager telephonyManager = TelephonyManager.from(mPrefFragment.getContext())
                 .createForSubscriptionId(subId);
-        Phone phone = PhoneGlobals.getPhone(subId);
-        if (phone == null) return;
         if (telephonyManager.getPhoneType() != PhoneConstants.PHONE_TYPE_GSM) {
             log("Not a GSM phone");
             addAPNExpand = false;
@@ -104,7 +101,7 @@
             }
 
             if (carrierConfig.getBoolean(CarrierConfigManager.KEY_CSP_ENABLED_BOOL)) {
-                if (phone.isCspPlmnEnabled()) {
+                if (telephonyManager.isManualNetworkSelectionAllowed()) {
                     log("[CSP] Enabling Operator Selection menu.");
                     mNetworkOperator.setEnabled(true);
                 } else {
@@ -151,7 +148,7 @@
 
         if (addNetworkOperatorsCategory) {
             mPrefScreen.addPreference(mNetworkOperator);
-            mNetworkOperator.update(subId, queryService);
+            mNetworkOperator.update(subId);
         } else {
             mPrefScreen.removePreference(mNetworkOperator);
         }
diff --git a/src/com/android/phone/MobileDataPreference.java b/src/com/android/phone/MobileDataPreference.java
index 4e82f20..e1ceab0 100644
--- a/src/com/android/phone/MobileDataPreference.java
+++ b/src/com/android/phone/MobileDataPreference.java
@@ -63,6 +63,11 @@
         super(context, attrs, com.android.internal.R.attr.switchPreferenceStyle);
     }
 
+    // Must be called to avoid binder leakage.
+    void dispose() {
+        mListener.setListener(false, mSubId, getContext());
+    }
+
     @Override
     protected void onRestoreInstanceState(Parcelable s) {
         CellDataState state = (CellDataState) s;
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index 148d1ad..3d37c4d 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -24,12 +24,10 @@
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.database.ContentObserver;
@@ -38,7 +36,6 @@
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.Message;
 import android.os.PersistableBundle;
 import android.os.SystemProperties;
@@ -469,53 +466,6 @@
 
         private final PhoneCallStateListener mPhoneStateListener = new PhoneCallStateListener();
 
-        /**
-         * Service connection code for the NetworkQueryService.
-         * Handles the work of binding to a local object so that we can make
-         * the appropriate service calls.
-         */
-
-        /** Local service interface */
-        private INetworkQueryService mNetworkQueryService = null;
-
-        private void setNetworkQueryService() {
-            mButtonNetworkSelect = (NetworkSelectListPreference) getPreferenceScreen()
-                    .findPreference(NetworkOperators.BUTTON_NETWORK_SELECT_KEY);
-            if (mButtonNetworkSelect != null) {
-                mButtonNetworkSelect.setNetworkQueryService(mNetworkQueryService);
-            }
-
-        }
-        /** Service connection */
-        private final ServiceConnection mNetworkQueryServiceConnection = new ServiceConnection() {
-
-            /** Handle the task of binding the local object to the service */
-            public void onServiceConnected(ComponentName className, IBinder service) {
-                if (DBG) log("connection created, binding local service.");
-                mNetworkQueryService = ((NetworkQueryService.LocalBinder) service).getService();
-                setNetworkQueryService();
-            }
-
-            /** Handle the task of cleaning up the local binding */
-            public void onServiceDisconnected(ComponentName className) {
-                if (DBG) log("connection disconnected, cleaning local binding.");
-                mNetworkQueryService = null;
-                setNetworkQueryService();
-            }
-        };
-
-        private void bindNetworkQueryService() {
-            getContext().startService(new Intent(getContext(), NetworkQueryService.class));
-            getContext().bindService(new Intent(getContext(), NetworkQueryService.class).setAction(
-                        NetworkQueryService.ACTION_LOCAL_BINDER),
-                        mNetworkQueryServiceConnection, Context.BIND_AUTO_CREATE);
-        }
-
-        private void unbindNetworkQueryService() {
-            // unbind the service.
-            getContext().unbindService(mNetworkQueryServiceConnection);
-        }
-
         @Override
         public void onPositiveButtonClick(DialogFragment dialog) {
             mTelephonyManager.setDataRoamingEnabled(true);
@@ -843,8 +793,6 @@
                 mExpandAdvancedFields = true;
             }
 
-            bindNetworkQueryService();
-
             addPreferencesFromResource(R.xml.network_setting_fragment);
 
             mButton4glte = (SwitchPreference)findPreference(BUTTON_4G_LTE_KEY);
@@ -947,8 +895,10 @@
 
         @Override
         public void onDestroy() {
-            unbindNetworkQueryService();
             super.onDestroy();
+            if (mMobileDataPref != null) {
+                mMobileDataPref.dispose();
+            }
         }
 
         @Override
@@ -1120,7 +1070,7 @@
                 if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
                     updateCdmaOptions(this, prefSet, mSubId);
                 } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
-                    updateGsmUmtsOptions(this, prefSet, phoneSubId, mNetworkQueryService);
+                    updateGsmUmtsOptions(this, prefSet, phoneSubId);
                 } else {
                     throw new IllegalStateException("Unexpected phone type: " + phoneType);
                 }
@@ -1136,7 +1086,7 @@
                 mButtonPreferredNetworkMode.setOnPreferenceChangeListener(this);
 
                 updateCdmaOptions(this, prefSet, mSubId);
-                updateGsmUmtsOptions(this, prefSet, phoneSubId, mNetworkQueryService);
+                updateGsmUmtsOptions(this, prefSet, phoneSubId);
             } else {
                 prefSet.removePreference(mButtonPreferredNetworkMode);
                 updateEnabledNetworksEntries();
@@ -1350,8 +1300,7 @@
                     mButtonEnabledNetworks.setEntryValues(
                             R.array.enabled_networks_values);
                 }
-                updateGsmUmtsOptions(this, getPreferenceScreen(), mSubId,
-                        mNetworkQueryService);
+                updateGsmUmtsOptions(this, getPreferenceScreen(), mSubId);
             } else {
                 throw new IllegalStateException("Unexpected phone type: " + phoneType);
             }
@@ -2095,7 +2044,7 @@
                 return;
             }
 
-            updateGsmUmtsOptions(this, prefSet, mSubId, mNetworkQueryService);
+            updateGsmUmtsOptions(this, prefSet, mSubId);
 
             PreferenceCategory networkOperatorCategory =
                     (PreferenceCategory) prefSet.findPreference(
@@ -2248,14 +2197,14 @@
         }
 
         private void updateGsmUmtsOptions(PreferenceFragment prefFragment,
-                PreferenceScreen prefScreen, final int subId, INetworkQueryService queryService) {
+                PreferenceScreen prefScreen, final int subId) {
             // We don't want to re-create GsmUmtsOptions if already exists. Otherwise, the
             // preferences inside it will also be re-created which causes unexpected behavior.
             // For example, the open dialog gets dismissed or detached after pause / resume.
             if (mGsmUmtsOptions == null) {
-                mGsmUmtsOptions = new GsmUmtsOptions(prefFragment, prefScreen, subId, queryService);
+                mGsmUmtsOptions = new GsmUmtsOptions(prefFragment, prefScreen, subId);
             } else {
-                mGsmUmtsOptions.update(subId, queryService);
+                mGsmUmtsOptions.update(subId);
             }
         }
 
diff --git a/src/com/android/phone/NetworkOperators.java b/src/com/android/phone/NetworkOperators.java
index 6d798b0..938ca34 100644
--- a/src/com/android/phone/NetworkOperators.java
+++ b/src/com/android/phone/NetworkOperators.java
@@ -94,12 +94,11 @@
     }
 
     /**
-     * Update NetworkOperators instance if like subId or queryService are updated.
+     * Update NetworkOperators instance if like subId is updated.
      *
      * @param subId Corresponding subscription ID of this network.
-     * @param queryService The service to do network queries.
      */
-    protected void update(final int subId, INetworkQueryService queryService) {
+    protected void update(final int subId) {
         mSubId = subId;
         mTelephonyManager = TelephonyManager.from(getContext()).createForSubscriptionId(mSubId);
 
@@ -118,7 +117,7 @@
             }
         } else {
             if (mNetworkSelect != null) {
-                mNetworkSelect.initialize(mSubId, queryService, this, mProgressDialog);
+                mNetworkSelect.initialize(mSubId, this, mProgressDialog);
             }
         }
         getNetworkSelectionMode();
diff --git a/src/com/android/phone/NetworkSelectListPreference.java b/src/com/android/phone/NetworkSelectListPreference.java
index 5b841c9..9af1c77 100644
--- a/src/com/android/phone/NetworkSelectListPreference.java
+++ b/src/com/android/phone/NetworkSelectListPreference.java
@@ -24,7 +24,6 @@
 import android.os.Message;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.RemoteException;
 import android.preference.ListPreference;
 import android.preference.Preference;
 import android.telephony.CellInfo;
@@ -39,15 +38,19 @@
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.widget.Toast;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.telephony.OperatorInfo;
+import com.android.phone.NetworkScanHelper.NetworkScanCallback;
 import com.android.settingslib.utils.ThreadUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
 
 /**
@@ -65,16 +68,20 @@
     private static final int EVENT_MANUALLY_NETWORK_SELECTION_DONE = 1;
     private static final int EVENT_NETWORK_SCAN_RESULTS = 2;
     private static final int EVENT_NETWORK_SCAN_COMPLETED = 3;
+    private static final int EVENT_NETWORK_SCAN_ERROR = 4;
 
     //dialog ids
     private static final int DIALOG_NETWORK_SELECTION = 100;
     private static final int DIALOG_NETWORK_LIST_LOAD = 200;
 
+    private final ExecutorService mNetworkScanExecutor = Executors.newFixedThreadPool(1);
+
     private List<CellInfo> mCellInfoList;
     private CellInfo mCellInfo;
 
     private int mSubId;
     private TelephonyManager mTelephonyManager;
+    private NetworkScanHelper mNetworkScanHelper;
     private NetworkOperators mNetworkOperators;
     private List<String> mForbiddenPlmns;
 
@@ -113,11 +120,7 @@
             switch (msg.what) {
                 case EVENT_MANUALLY_NETWORK_SELECTION_DONE:
                     if (DBG) logd("hideProgressPanel");
-                    try {
-                        dismissProgressBar();
-                    } catch (IllegalArgumentException e) {
-                    }
-                    setEnabled(true);
+                    dismissProgressDialog();
 
                     boolean isSuccessed = (boolean) msg.obj;
                     if (isSuccessed) {
@@ -138,72 +141,51 @@
                     results.removeIf(cellInfo -> cellInfo == null);
                     mCellInfoList = new ArrayList<>(results);
                     if (DBG) logd("CALLBACK_SCAN_RESULTS" + mCellInfoList.toString());
-
                     break;
 
                 case EVENT_NETWORK_SCAN_COMPLETED:
-                    try {
-                        if (mNetworkQueryService != null) {
-                            mNetworkQueryService.unregisterCallback(mCallback);
-                        }
-                    } catch (RemoteException e) {
-                        loge("onComplete: exception from unregisterCallback " + e);
-                    }
                     if (DBG) logd("scan complete, load the cellInfosList");
-                    // Modify UI to indicate users that the scan has completed.
+                    dismissProgressDialog();
                     networksListLoaded();
+                    break;
+                case EVENT_NETWORK_SCAN_ERROR:
+                    dismissProgressDialog();
+                    displayNetworkQueryFailed();
+                    mNetworkOperators.getNetworkSelectionMode();
+                    break;
             }
             return;
         }
     };
 
-    INetworkQueryService mNetworkQueryService = null;
-    /**
-     * This implementation of INetworkQueryServiceCallback is used to receive
-     * callback notifications from the network query service.
-     */
-    private final INetworkQueryServiceCallback mCallback = new INetworkQueryServiceCallback.Stub() {
-
-        /** Returns the scan results to the user, this callback will be called only one time. */
+    private final NetworkScanHelper.NetworkScanCallback mCallback = new NetworkScanCallback() {
         public void onResults(List<CellInfo> results) {
             if (DBG) logd("get scan results: " + results.toString());
             Message msg = mHandler.obtainMessage(EVENT_NETWORK_SCAN_RESULTS, results);
             msg.sendToTarget();
         }
 
-        /**
-         * Informs the user that the scan has stopped.
-         *
-         * This callback will be called when the scan is finished or cancelled by the user.
-         * The related NetworkScanRequest will be deleted after this callback.
-         */
         public void onComplete() {
             if (DBG) logd("network scan completed.");
             Message msg = mHandler.obtainMessage(EVENT_NETWORK_SCAN_COMPLETED);
             msg.sendToTarget();
         }
 
-        /**
-         * This callback will not be called, since the old Scan API won't send this callback.
-         */
-        public void onError(int error) {}
+        public void onError(int error) {
+            if (DBG) logd("network scan error.");
+            Message msg = mHandler.obtainMessage(EVENT_NETWORK_SCAN_ERROR);
+            msg.sendToTarget();
+        }
     };
 
     @Override
     //implemented for DialogInterface.OnCancelListener
     public void onCancel(DialogInterface dialog) {
         if (DBG) logd("user manually close the dialog");
-        // request that the service stop the query with this callback object.
-        try {
-            if (mNetworkQueryService != null) {
-                mNetworkQueryService.stopNetworkQuery();
-                mNetworkQueryService.unregisterCallback(mCallback);
-            }
-            // If cancelled, we query NetworkSelectMode and update states of AutoSelect button.
-            mNetworkOperators.getNetworkSelectionMode();
-        } catch (RemoteException e) {
-            loge("onCancel: exception from stopNetworkQuery " + e);
-        }
+        mNetworkScanHelper.stopNetworkQuery();
+
+        // If cancelled, we query NetworkSelectMode and update states of AutoSelect button.
+        mNetworkOperators.getNetworkSelectionMode();
     }
 
     @Override
@@ -215,23 +197,17 @@
         }
     }
 
-    // This method is provided besides initialize() because bind to network query service
-    // may be binded after initialize(). In that case this method needs to be called explicitly
-    // to set mNetworkQueryService. Otherwise mNetworkQueryService will remain null.
-    public void setNetworkQueryService(INetworkQueryService queryService) {
-        mNetworkQueryService = queryService;
-    }
-
     // This initialize method needs to be called for this preference to work properly.
-    protected void initialize(int subId, INetworkQueryService queryService,
-                              NetworkOperators networkOperators, ProgressDialog progressDialog) {
+    protected void initialize(int subId, NetworkOperators networkOperators,
+            ProgressDialog progressDialog) {
         mSubId = subId;
-        mNetworkQueryService = queryService;
         mNetworkOperators = networkOperators;
         // This preference should share the same progressDialog with networkOperators category.
         mProgressDialog = progressDialog;
 
         mTelephonyManager = TelephonyManager.from(getContext()).createForSubscriptionId(mSubId);
+        mNetworkScanHelper = new NetworkScanHelper(
+                mTelephonyManager, mCallback, mNetworkScanExecutor);
 
         setSummary(mTelephonyManager.getNetworkOperatorName());
 
@@ -245,79 +221,32 @@
     }
 
     private void destroy() {
-        try {
-            dismissProgressBar();
-        } catch (IllegalArgumentException e) {
-            loge("onDestroy: exception from dismissProgressBar " + e);
+        dismissProgressDialog();
+
+        if (mNetworkScanHelper != null) {
+            mNetworkScanHelper.stopNetworkQuery();
         }
 
-        try {
-            if (mNetworkQueryService != null) {
-                // used to un-register callback
-                mNetworkQueryService.unregisterCallback(mCallback);
-            }
-        } catch (RemoteException e) {
-            loge("onDestroy: exception from unregisterCallback " + e);
-        }
+        mNetworkScanExecutor.shutdown();
     }
 
     private void displayEmptyNetworkList() {
-        String status = getContext().getResources().getString(R.string.empty_networks_list);
-
-        final PhoneGlobals app = PhoneGlobals.getInstance();
-        app.notificationMgr.postTransientNotification(
-                NotificationMgr.NETWORK_SELECTION_NOTIFICATION, status);
+        Toast.makeText(getContext(), R.string.empty_networks_list, Toast.LENGTH_LONG).show();
     }
 
-    private void displayNetworkSelectionInProgress() {
-        showProgressDialog(DIALOG_NETWORK_SELECTION);
-    }
-
-    private void displayNetworkQueryFailed(int error) {
-        String status = getContext().getResources().getString(R.string.network_query_error);
-
-        try {
-            dismissProgressBar();
-        } catch (IllegalArgumentException e1) {
-            // do nothing
-        }
-
-        final PhoneGlobals app = PhoneGlobals.getInstance();
-        app.notificationMgr.postTransientNotification(
-                NotificationMgr.NETWORK_SELECTION_NOTIFICATION, status);
+    private void displayNetworkQueryFailed() {
+        Toast.makeText(getContext(), R.string.network_query_error, Toast.LENGTH_LONG).show();
     }
 
     private void loadNetworksList() {
         if (DBG) logd("load networks list...");
-        try {
-            if (mNetworkQueryService != null) {
-                mNetworkQueryService.startNetworkQuery(
-                        mCallback, mSubId, false /* isIncrementalResult */);
-            } else {
-                displayNetworkQueryFailed(NetworkQueryService.QUERY_EXCEPTION);
-            }
-        } catch (RemoteException e) {
-            loge("loadNetworksList: exception from startNetworkQuery " + e);
-            displayNetworkQueryFailed(NetworkQueryService.QUERY_EXCEPTION);
-        }
+        mNetworkScanHelper.startNetworkScan(
+                NetworkScanHelper.NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS);
     }
 
     private void networksListLoaded() {
         if (DBG) logd("networks list loaded");
 
-        // update the state of the preferences.
-        if (DBG) logd("hideProgressPanel");
-
-        // Always try to dismiss the dialog because activity may
-        // be moved to background after dialog is shown.
-        try {
-            dismissProgressBar();
-        } catch (IllegalArgumentException e) {
-            // 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.
-            loge("Fail to dismiss network load list dialog " + e);
-        }
         mNetworkOperators.getNetworkSelectionMode();
         if (mCellInfoList != null) {
             // create a preference for each item in the list.
@@ -345,9 +274,13 @@
         }
     }
 
-    private void dismissProgressBar() {
+    private void dismissProgressDialog() {
         if (mProgressDialog != null && mProgressDialog.isShowing()) {
-            mProgressDialog.dismiss();
+            try {
+                mProgressDialog.dismiss();
+            } catch (IllegalArgumentException ex) {
+                loge("Can't close the progress dialog " + ex);
+            }
         }
     }
 
@@ -356,7 +289,7 @@
             mProgressDialog = new ProgressDialog(getContext());
         } else {
             // Dismiss progress bar if it's showing now.
-            dismissProgressBar();
+            dismissProgressDialog();
         }
 
         switch (id) {
diff --git a/src/com/android/phone/NetworkSelectSetting.java b/src/com/android/phone/NetworkSelectSetting.java
index c8a29ce..66cd8a1 100644
--- a/src/com/android/phone/NetworkSelectSetting.java
+++ b/src/com/android/phone/NetworkSelectSetting.java
@@ -17,17 +17,12 @@
 
 import android.app.ActionBar;
 import android.app.Activity;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.Message;
-import android.os.RemoteException;
 import android.preference.Preference;
 import android.preference.PreferenceCategory;
 import android.preference.PreferenceFragment;
@@ -47,6 +42,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.telephony.OperatorInfo;
+import com.android.phone.NetworkScanHelper.NetworkScanCallback;
 import com.android.settingslib.utils.ThreadUtils;
 
 import java.util.ArrayList;
@@ -54,6 +50,8 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
 /**
  * "Choose network" settings UI for the Phone app.
@@ -86,6 +84,8 @@
     private TelephonyManager mTelephonyManager;
     private List<String> mForbiddenPlmns;
     private boolean mShow4GForLTE;
+    private NetworkScanHelper mNetworkScanHelper;
+    private final ExecutorService mNetworkScanExecutor = Executors.newFixedThreadPool(1);
 
     private final Runnable mUpdateNetworkOperatorsRunnable = () -> {
         updateNetworkOperatorsPreferenceCategory();
@@ -118,6 +118,8 @@
         mStatusMessagePreference = new Preference(getContext());
         mSelectedNetworkOperatorPreference = null;
         mTelephonyManager = TelephonyManager.from(getContext()).createForSubscriptionId(mSubId);
+        mNetworkScanHelper = new NetworkScanHelper(
+                mTelephonyManager, mCallback, mNetworkScanExecutor);
         try {
             Context con = getActivity().createPackageContext("com.android.systemui", 0);
             int id = con.getResources().getIdentifier("config_show4GForLTE",
@@ -172,7 +174,7 @@
             @Override
             protected void onPostExecute(List<String> result) {
                 mForbiddenPlmns = result;
-                bindNetworkQueryService();
+                loadNetworksList();
             }
         }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
@@ -260,8 +262,6 @@
         if (DBG) logd("onStop");
         getView().removeCallbacks(mUpdateNetworkOperatorsRunnable);
         stopNetworkQuery();
-        // Unbind the NetworkQueryService
-        unbindNetworkQueryService();
     }
 
     private final Handler mHandler = new Handler() {
@@ -320,52 +320,23 @@
     private void loadNetworksList() {
         if (DBG) logd("load networks list...");
         setProgressBarVisible(true);
-        try {
-            if (mNetworkQueryService != null) {
-                if (DBG) logd("start network query");
-                mNetworkQueryService
-                        .startNetworkQuery(mCallback, mSubId, true /* is incremental result */);
-            } else {
-                if (DBG) logd("unable to start network query, mNetworkQueryService is null");
-                addMessagePreference(R.string.network_query_error);
-            }
-        } catch (RemoteException e) {
-            loge("loadNetworksList: exception from startNetworkQuery " + e);
-            addMessagePreference(R.string.network_query_error);
-        }
+        mNetworkScanHelper.startNetworkScan(
+                NetworkScanHelper.NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS);
     }
 
-    /**
-     * This implementation of INetworkQueryServiceCallback is used to receive
-     * callback notifications from the network query service.
-     */
-    private final INetworkQueryServiceCallback mCallback = new INetworkQueryServiceCallback.Stub() {
-
-        /** Returns the scan results to the user, this callback will be called at lease one time. */
+    private final NetworkScanHelper.NetworkScanCallback mCallback = new NetworkScanCallback() {
         public void onResults(List<CellInfo> results) {
             if (DBG) logd("get scan results.");
             Message msg = mHandler.obtainMessage(EVENT_NETWORK_SCAN_RESULTS, results);
             msg.sendToTarget();
         }
 
-        /**
-         * Informs the user that the scan has stopped.
-         *
-         * This callback will be called when the scan is finished or cancelled by the user.
-         * The related NetworkScanRequest will be deleted after this callback.
-         */
         public void onComplete() {
             if (DBG) logd("network scan completed.");
             Message msg = mHandler.obtainMessage(EVENT_NETWORK_SCAN_COMPLETED);
             msg.sendToTarget();
         }
 
-        /**
-         * Informs the user that there is some error about the scan.
-         *
-         * This callback will be called whenever there is any error about the scan, and the scan
-         * will be terminated. onComplete() will NOT be called.
-         */
         public void onError(int error) {
             if (DBG) logd("get onError callback with error code: " + error);
             Message msg = mHandler.obtainMessage(EVENT_NETWORK_SCAN_ERROR, error, 0 /* arg2 */);
@@ -373,9 +344,6 @@
         }
     };
 
-    /**
-     * Updates network operators from {@link INetworkQueryServiceCallback#onResults()}.
-     */
     private void updateNetworkOperators() {
         if (DBG) logd("updateNetworkOperators");
         if (getActivity() != null) {
@@ -580,66 +548,18 @@
         return new ArrayList<>(map.values());
     }
 
-    /**
-     * Service connection code for the NetworkQueryService.
-     * Handles the work of binding to a local object so that we can make
-     * the appropriate service calls.
-     */
-
-    /** Local service interface */
-    private INetworkQueryService mNetworkQueryService = null;
-    /** Flag indicating whether we have called bind on the service. */
-    boolean mShouldUnbind;
-
-    /** Service connection */
-    private final ServiceConnection mNetworkQueryServiceConnection = new ServiceConnection() {
-
-        /** Handle the task of binding the local object to the service */
-        public void onServiceConnected(ComponentName className, IBinder service) {
-            if (DBG) logd("connection created, binding local service.");
-            mNetworkQueryService = ((NetworkQueryService.LocalBinder) service).getService();
-            // Load the network list only when the service is well connected.
-            loadNetworksList();
-        }
-
-        /** Handle the task of cleaning up the local binding */
-        public void onServiceDisconnected(ComponentName className) {
-            if (DBG) logd("connection disconnected, cleaning local binding.");
-            mNetworkQueryService = null;
-        }
-    };
-
-    private void bindNetworkQueryService() {
-        if (DBG) logd("bindNetworkQueryService");
-        getContext().bindService(new Intent(getContext(), NetworkQueryService.class).setAction(
-                NetworkQueryService.ACTION_LOCAL_BINDER),
-                mNetworkQueryServiceConnection, Context.BIND_AUTO_CREATE);
-        mShouldUnbind = true;
-    }
-
-    private void unbindNetworkQueryService() {
-        if (DBG) logd("unbindNetworkQueryService");
-        if (mShouldUnbind) {
-            if (DBG) logd("mShouldUnbind is true");
-            // unbind the service.
-            getContext().unbindService(mNetworkQueryServiceConnection);
-            mShouldUnbind = false;
-        }
-    }
-
     private void stopNetworkQuery() {
-        // Stop the network query process
-        try {
-            if (mNetworkQueryService != null) {
-                if (DBG) logd("Stop network query");
-                mNetworkQueryService.stopNetworkQuery();
-                mNetworkQueryService.unregisterCallback(mCallback);
-            }
-        } catch (RemoteException e) {
-            loge("Exception from stopNetworkQuery " + e);
+        if (mNetworkScanHelper != null) {
+            mNetworkScanHelper.stopNetworkQuery();
         }
     }
 
+    @Override
+    public void onDestroy() {
+        mNetworkScanExecutor.shutdown();
+        super.onDestroy();
+    }
+
     private void logd(String msg) {
         Log.d(TAG, msg);
     }
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index cef0e53..8866d30 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -4980,6 +4980,23 @@
     }
 
     @Override
+    public boolean isManualNetworkSelectionAllowed(int subId) {
+        boolean isAllowed = true;
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            TelephonyPermissions.enforeceCallingOrSelfReadPhoneStatePermissionOrCarrierPrivilege(
+                    mApp, subId, "isManualNetworkSelectionAllowed");
+            Phone phone = getPhone(subId);
+            if (phone != null) {
+                isAllowed = phone.isCspPlmnEnabled();
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+        return isAllowed;
+    }
+
+    @Override
     public UiccSlotInfo[] getUiccSlotsInfo() {
         enforceReadPrivilegedPermission();
 
diff --git a/src/com/android/phone/settings/PhoneAccountSettingsFragment.java b/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
index 670f98d..d891da9 100644
--- a/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
+++ b/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
@@ -18,6 +18,7 @@
 import android.telecom.TelecomManager;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
@@ -76,6 +77,15 @@
     private SwitchPreference mSipReceiveCallsPreference;
     private SipPreferences mSipPreferences;
 
+    private final SubscriptionManager.OnSubscriptionsChangedListener
+            mOnSubscriptionsChangeListener =
+            new SubscriptionManager.OnSubscriptionsChangedListener() {
+        @Override
+        public void onSubscriptionsChanged() {
+            updateAccounts();
+        }
+    };
+
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
@@ -122,34 +132,8 @@
          */
         mAccountList = (PreferenceCategory) getPreferenceScreen().findPreference(
                 ACCOUNTS_LIST_CATEGORY_KEY);
-        List<PhoneAccountHandle> allNonSimAccounts =
-                getCallingAccounts(false /* includeSims */, true /* includeDisabled */);
-        // Check to see if we should show the entire section at all.
-        if (shouldShowConnectionServiceList(allNonSimAccounts)) {
-            List<PhoneAccountHandle> enabledAccounts =
-                    getCallingAccounts(true /* includeSims */, false /* includeDisabled */);
-            // Initialize the account list with the set of enabled & SIM accounts.
-            initAccountList(enabledAccounts);
 
-            mDefaultOutgoingAccount = (AccountSelectionPreference)
-                    getPreferenceScreen().findPreference(DEFAULT_OUTGOING_ACCOUNT_KEY);
-            mDefaultOutgoingAccount.setListener(this);
-
-            // Only show the 'Make Calls With..." option if there are multiple accounts.
-            if (enabledAccounts.size() > 1) {
-                updateDefaultOutgoingAccountsModel();
-            } else {
-                mAccountList.removePreference(mDefaultOutgoingAccount);
-            }
-
-            Preference allAccounts = getPreferenceScreen().findPreference(ALL_CALLING_ACCOUNTS_KEY);
-            // If there are no third party (nonSim) accounts, then don't show enable/disable dialog.
-            if (allNonSimAccounts.isEmpty() && allAccounts != null) {
-                mAccountList.removePreference(allAccounts);
-            }
-        } else {
-            getPreferenceScreen().removePreference(mAccountList);
-        }
+        updateAccounts();
 
         if (isPrimaryUser() && SipUtil.isVoipSupported(getActivity())) {
             mSipPreferences = new SipPreferences(getActivity());
@@ -183,6 +167,16 @@
             getPreferenceScreen().removePreference(
                     getPreferenceScreen().findPreference(SIP_SETTINGS_CATEGORY_PREF_KEY));
         }
+
+        SubscriptionManager.from(getActivity()).addOnSubscriptionsChangedListener(
+                mOnSubscriptionsChangeListener);
+    }
+
+    @Override
+    public void onPause() {
+        SubscriptionManager.from(getActivity()).removeOnSubscriptionsChangedListener(
+                mOnSubscriptionsChangeListener);
+        super.onPause();
     }
 
     /**
@@ -391,6 +385,40 @@
         return mTelephonyManager.isMultiSimEnabled() || allNonSimAccounts.size() > 0;
     }
 
+    private void updateAccounts() {
+        if (mAccountList != null) {
+            mAccountList.removeAll();
+            List<PhoneAccountHandle> allNonSimAccounts =
+                    getCallingAccounts(false /* includeSims */, true /* includeDisabled */);
+            // Check to see if we should show the entire section at all.
+            if (shouldShowConnectionServiceList(allNonSimAccounts)) {
+                List<PhoneAccountHandle> enabledAccounts =
+                        getCallingAccounts(true /* includeSims */, false /* includeDisabled */);
+                // Initialize the account list with the set of enabled & SIM accounts.
+                initAccountList(enabledAccounts);
+
+                mDefaultOutgoingAccount = (AccountSelectionPreference)
+                        getPreferenceScreen().findPreference(DEFAULT_OUTGOING_ACCOUNT_KEY);
+                mDefaultOutgoingAccount.setListener(this);
+
+                // Only show the 'Make Calls With..." option if there are multiple accounts.
+                if (enabledAccounts.size() > 1) {
+                    updateDefaultOutgoingAccountsModel();
+                } else {
+                    mAccountList.removePreference(mDefaultOutgoingAccount);
+                }
+
+                Preference allAccounts = getPreferenceScreen().findPreference(ALL_CALLING_ACCOUNTS_KEY);
+                // If there are no third party (nonSim) accounts, then don't show enable/disable dialog.
+                if (allNonSimAccounts.isEmpty() && allAccounts != null) {
+                    mAccountList.removePreference(allAccounts);
+                }
+            } else {
+                getPreferenceScreen().removePreference(mAccountList);
+            }
+        }
+    }
+
     private List<PhoneAccountHandle> getCallingAccounts(
             boolean includeSims, boolean includeDisabledAccounts) {
         PhoneAccountHandle emergencyAccountHandle = getEmergencyPhoneAccount();
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index 7d6a86f..a82c346 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -169,6 +169,10 @@
             case android.telephony.DisconnectCause.SERVER_ERROR:
             case android.telephony.DisconnectCause.SERVER_UNREACHABLE:
             case android.telephony.DisconnectCause.TIMED_OUT:
+            case android.telephony.DisconnectCause.ALREADY_DIALING:
+            case android.telephony.DisconnectCause.CANT_CALL_WHILE_RINGING:
+            case android.telephony.DisconnectCause.CALLING_DISABLED:
+            case android.telephony.DisconnectCause.TOO_MANY_ONGOING_CALLS:
             case android.telephony.DisconnectCause.UNOBTAINABLE_NUMBER:
             case android.telephony.DisconnectCause.VOICEMAIL_NUMBER_MISSING:
             case android.telephony.DisconnectCause.DIAL_MODIFIED_TO_USSD:
@@ -320,6 +324,18 @@
             case android.telephony.DisconnectCause.DATA_LIMIT_REACHED:
                 resourceId = R.string.callFailed_data_limit_reached;
                 break;
+            case android.telephony.DisconnectCause.ALREADY_DIALING:
+                resourceId = R.string.callFailed_already_dialing;
+                break;
+            case android.telephony.DisconnectCause.CANT_CALL_WHILE_RINGING:
+                resourceId = R.string.callFailed_already_ringing;
+                break;
+            case android.telephony.DisconnectCause.CALLING_DISABLED:
+                resourceId = R.string.callFailed_calling_disabled;
+                break;
+            case android.telephony.DisconnectCause.TOO_MANY_ONGOING_CALLS:
+                resourceId = R.string.callFailed_too_many_calls;
+                break;
 
             default:
                 break;
@@ -684,6 +700,18 @@
             case android.telephony.DisconnectCause.WIFI_LOST:
                 resourceId = R.string.callFailed_wifi_lost;
                 break;
+            case android.telephony.DisconnectCause.ALREADY_DIALING:
+                resourceId = R.string.callFailed_already_dialing;
+                break;
+            case android.telephony.DisconnectCause.CANT_CALL_WHILE_RINGING:
+                resourceId = R.string.callFailed_already_ringing;
+                break;
+            case android.telephony.DisconnectCause.CALLING_DISABLED:
+                resourceId = R.string.callFailed_calling_disabled;
+                break;
+            case android.telephony.DisconnectCause.TOO_MANY_ONGOING_CALLS:
+                resourceId = R.string.callFailed_too_many_calls;
+                break;
 
             default:
                 break;
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 3192c75..8f46ecf 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -892,7 +892,7 @@
             if (originalConnection.isRttEnabledForCall()) {
                 originalConnection.setCurrentRttTextStream(textStream);
             } else {
-                originalConnection.sendRttModifyRequest(textStream);
+                originalConnection.startRtt(textStream);
             }
         } else {
             Log.w(this, "onStartRtt - not in IMS, so RTT cannot be enabled.");
@@ -901,7 +901,16 @@
 
     @Override
     public void onStopRtt() {
-        Log.i(this, "Stopping RTT currently not supported. Doing nothing.");
+        if (isImsConnection()) {
+            ImsPhoneConnection originalConnection = (ImsPhoneConnection) mOriginalConnection;
+            if (originalConnection.isRttEnabledForCall()) {
+                originalConnection.stopRtt();
+            } else {
+                Log.w(this, "onStopRtt - not in RTT call, ignoring");
+            }
+        } else {
+            Log.w(this, "onStopRtt - not in IMS, ignoring");
+        }
     }
 
     @Override
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 3ec00b9..16be893 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -1120,10 +1120,25 @@
         } catch (CallStateException e) {
             Log.e(this, e, "placeOutgoingConnection, phone.dial exception: " + e);
             int cause = android.telephony.DisconnectCause.OUTGOING_FAILURE;
-            if (e.getError() == CallStateException.ERROR_OUT_OF_SERVICE) {
-                cause = android.telephony.DisconnectCause.OUT_OF_SERVICE;
-            } else if (e.getError() == CallStateException.ERROR_POWER_OFF) {
-                cause = android.telephony.DisconnectCause.POWER_OFF;
+            switch (e.getError()) {
+                case CallStateException.ERROR_OUT_OF_SERVICE:
+                    cause = android.telephony.DisconnectCause.OUT_OF_SERVICE;
+                    break;
+                case CallStateException.ERROR_POWER_OFF:
+                    cause = android.telephony.DisconnectCause.POWER_OFF;
+                    break;
+                case CallStateException.ERROR_ALREADY_DIALING:
+                    cause = android.telephony.DisconnectCause.ALREADY_DIALING;
+                    break;
+                case CallStateException.ERROR_CALL_RINGING:
+                    cause = android.telephony.DisconnectCause.CANT_CALL_WHILE_RINGING;
+                    break;
+                case CallStateException.ERROR_CALLING_DISABLED:
+                    cause = android.telephony.DisconnectCause.CALLING_DISABLED;
+                    break;
+                case CallStateException.ERROR_TOO_MANY_CALLS:
+                    cause = android.telephony.DisconnectCause.TOO_MANY_ONGOING_CALLS;
+                    break;
             }
             connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
                     cause, e.getMessage(), phone.getPhoneId()));