Merge "Added Multi-SIM capability to Access Point Names" into lmp-mr1-dev
diff --git a/res/xml/phone_account_settings.xml b/res/xml/phone_account_settings.xml
index 18b75e6..f818baa 100644
--- a/res/xml/phone_account_settings.xml
+++ b/res/xml/phone_account_settings.xml
@@ -39,11 +39,6 @@
             android:summary="@string/wifi_calling_call_assistant_none"
             android:persistent="false" />
 
-        <SwitchPreference
-            android:key="wifi_calling_call_assistant_switch"
-            android:title="@string/wifi_calling_call_assistant"
-            android:persistent="false" />
-
         <Preference
             android:key="wifi_calling_configure_call_assistant_preference"
             android:title="@string/wifi_calling_call_assistant_configure"
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index 9956397..1d054a6 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -131,6 +131,12 @@
      */
     public static final String IGNORE_PROVIDER_EXTRA = "com.android.phone.ProviderToIgnore";
 
+    /**
+     * String Extra put into ACTION_ADD_VOICEMAIL to indicate that the voicemail setup screen should
+     * be opened.
+     */
+    public static final String SETUP_VOICEMAIL_EXTRA = "com.android.phone.SetupVoicemail";
+
     // string constants
     private static final String NUM_PROJECTION[] = {CommonDataKinds.Phone.NUMBER};
 
@@ -287,6 +293,11 @@
      */
     private boolean mShowVoicemailPreference = false;
 
+    /**
+     * Used to indicate that the voicemail setup screen should be shown.
+     */
+    private boolean mSetupVoicemail = false;
+
     /*
      * Click Listeners, handle click based on objects attached to UI.
      */
@@ -713,6 +724,9 @@
         } else {
             saveVoiceMailAndForwardingNumberStage2();
         }
+
+        // Refresh the MWI indicator if it is already showing.
+        PhoneGlobals.getInstance().refreshMwiIndicator(mSubscriptionInfoHelper.getSubId());
     }
 
     private final Handler mGetOptionComplete = new Handler() {
@@ -1107,6 +1121,8 @@
         // ACTION_ADD_VOICEMAIL action.
         mShowVoicemailPreference = (icicle == null) &&
                 TextUtils.equals(getIntent().getAction(), ACTION_ADD_VOICEMAIL);
+        mSetupVoicemail = mShowVoicemailPreference &&
+                getIntent().getBooleanExtra(SETUP_VOICEMAIL_EXTRA, false);
 
         mSubscriptionInfoHelper = new SubscriptionInfoHelper(getIntent());
         mSubscriptionInfoHelper.setActionBarTitle(
@@ -1268,7 +1284,10 @@
         // We only bring up the dialog the first time we are called (not after orientation change)
         if (mShowVoicemailPreference) {
             if (DBG) log("ACTION_ADD_VOICEMAIL Intent is thrown");
-            if (mVoicemailProviders.hasMoreThanOneVoicemailProvider()) {
+            if (mSetupVoicemail) {
+                simulatePreferenceClick(mVoicemailSettingsScreen);
+                mSetupVoicemail = false;
+            } else if (mVoicemailProviders.hasMoreThanOneVoicemailProvider()) {
                 if (DBG) log("Voicemail data has more than one provider.");
                 simulatePreferenceClick(mVoicemailProviders);
             } else {
diff --git a/src/com/android/phone/CallNotifier.java b/src/com/android/phone/CallNotifier.java
index 01a2449..5b60f8a 100644
--- a/src/com/android/phone/CallNotifier.java
+++ b/src/com/android/phone/CallNotifier.java
@@ -49,10 +49,18 @@
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.PhoneStateListener;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
 import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
 import android.util.EventLog;
 import android.util.Log;
 
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
 /**
  * Phone app module that listens for phone state changes and various other
  * events from the telephony layer, and triggers any resulting UI behavior
@@ -85,6 +93,8 @@
 
     // object used to synchronize access to mCallerInfoQueryState
     private Object mCallerInfoQueryStateGuard = new Object();
+    private Map<Integer, CallNotifierPhoneStateListener> mPhoneStateListeners =
+            new ArrayMap<Integer, CallNotifierPhoneStateListener>();
 
     private PhoneGlobals mApplication;
     private CallManager mCM;
@@ -103,20 +113,22 @@
 
     // Cached AudioManager
     private AudioManager mAudioManager;
-
     private final BluetoothManager mBluetoothManager;
+    private SubscriptionManager mSubscriptionManager;
+    private TelephonyManager mTelephonyManager;
 
     /**
      * Initialize the singleton CallNotifier instance.
      * This is only done once, at startup, from PhoneApp.onCreate().
      */
-    /* package */ static CallNotifier init(PhoneGlobals app, Phone phone,
-            CallLogger callLogger, CallStateMonitor callStateMonitor,
+    /* package */ static CallNotifier init(
+            PhoneGlobals app,
+            CallLogger callLogger,
+            CallStateMonitor callStateMonitor,
             BluetoothManager bluetoothManager) {
         synchronized (CallNotifier.class) {
             if (sInstance == null) {
-                sInstance = new CallNotifier(app, phone, callLogger, callStateMonitor,
-                        bluetoothManager);
+                sInstance = new CallNotifier(app, callLogger, callStateMonitor, bluetoothManager);
             } else {
                 Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);
             }
@@ -125,29 +137,38 @@
     }
 
     /** Private constructor; @see init() */
-    private CallNotifier(PhoneGlobals app, Phone phone, CallLogger callLogger,
-            CallStateMonitor callStateMonitor, BluetoothManager bluetoothManager) {
+    private CallNotifier(
+            PhoneGlobals app,
+            CallLogger callLogger,
+            CallStateMonitor callStateMonitor,
+            BluetoothManager bluetoothManager) {
         mApplication = app;
         mCM = app.mCM;
         mCallLogger = callLogger;
         mBluetoothManager = bluetoothManager;
 
         mAudioManager = (AudioManager) mApplication.getSystemService(Context.AUDIO_SERVICE);
+        mTelephonyManager =
+                (TelephonyManager) mApplication.getSystemService(Context.TELEPHONY_SERVICE);
+        mSubscriptionManager = (SubscriptionManager) mApplication.getSystemService(
+                Context.TELEPHONY_SUBSCRIPTION_SERVICE);
 
         callStateMonitor.addListener(this);
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
         if (adapter != null) {
             adapter.getProfileProxy(mApplication.getApplicationContext(),
-                                    mBluetoothProfileServiceListener,
-                                    BluetoothProfile.HEADSET);
+                    mBluetoothProfileServiceListener,
+                    BluetoothProfile.HEADSET);
         }
 
-        TelephonyManager telephonyManager = (TelephonyManager) app.getSystemService(
-                Context.TELEPHONY_SERVICE);
-        telephonyManager.listen(mPhoneStateListener,
-                PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
-                | PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR);
+        mSubscriptionManager.registerOnSubscriptionsChangedListener(
+                new OnSubscriptionsChangedListener() {
+                    @Override
+                    public void onSubscriptionsChanged() {
+                        updatePhoneStateListeners();
+                    }
+                });
     }
 
     private void createSignalInfoToneGenerator() {
@@ -239,20 +260,6 @@
         }
     }
 
-    PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
-        @Override
-        public void onMessageWaitingIndicatorChanged(boolean visible) {
-            if (VDBG) log("onMessageWaitingIndicatorChanged(): " + visible);
-            mApplication.notificationMgr.updateMwi(visible);
-        }
-
-        @Override
-        public void onCallForwardingIndicatorChanged(boolean visible) {
-            if (VDBG) log("onCallForwardingIndicatorChanged(): " + visible);
-            mApplication.notificationMgr.updateCfi(visible);
-        }
-    };
-
     /**
      * Handles a "new ringing connection" event from the telephony layer.
      */
@@ -894,18 +901,24 @@
     /**
      * Displays a notification when the phone receives a notice that a supplemental
      * service has failed.
-     * TODO: This is a NOOP if it isn't for conferences right now.
+     * TODO: This is a NOOP if it isn't for conferences or resuming call failures right now.
      */
     private void onSuppServiceFailed(AsyncResult r) {
-        if (r.result != Phone.SuppService.CONFERENCE) {
-            if (DBG) log("onSuppServiceFailed: not a merge failure event");
+        if (r.result != Phone.SuppService.CONFERENCE && r.result != Phone.SuppService.RESUME) {
+            if (DBG) log("onSuppServiceFailed: not a merge or resume failure event");
             return;
         }
 
-        if (DBG) log("onSuppServiceFailed: displaying merge failure message");
-
-        String mergeFailedString = mApplication.getResources().getString(
-                R.string.incall_error_supp_service_conference);
+        String mergeFailedString = "";
+        if (r.result == Phone.SuppService.CONFERENCE) {
+            if (DBG) log("onSuppServiceFailed: displaying merge failure message");
+            mergeFailedString = mApplication.getResources().getString(
+                    R.string.incall_error_supp_service_conference);
+        } else if (r.result == Phone.SuppService.RESUME) {
+            if (DBG) log("onSuppServiceFailed: displaying merge failure message");
+            mergeFailedString = mApplication.getResources().getString(
+                    R.string.incall_error_supp_service_switch);
+        }
         PhoneDisplayMessage.displayErrorMessage(mApplication, mergeFailedString);
 
         // start a timer that kills the dialog
@@ -913,6 +926,58 @@
                 SHOW_MESSAGE_NOTIFICATION_TIME);
     }
 
+    public void updatePhoneStateListeners() {
+        List<SubscriptionInfo> subInfos = mSubscriptionManager.getActiveSubscriptionInfoList();
+
+        // Unregister phone listeners for inactive subscriptions.
+        Iterator<Integer> itr = mPhoneStateListeners.keySet().iterator();
+        while (itr.hasNext()) {
+            int subId = itr.next();
+            if (subInfos == null || !containsSubId(subInfos, subId)) {
+                // Hide the outstanding notifications.
+                mApplication.notificationMgr.updateMwi(subId, false);
+                mApplication.notificationMgr.updateCfi(subId, false);
+
+                // Listening to LISTEN_NONE removes the listener.
+                mTelephonyManager.listen(
+                        mPhoneStateListeners.get(subId), PhoneStateListener.LISTEN_NONE);
+                itr.remove();
+            }
+        }
+
+        if (subInfos == null) {
+            return;
+        }
+
+        // Register new phone listeners for active subscriptions.
+        for (int i = 0; i < subInfos.size(); i++) {
+            int subId = subInfos.get(i).getSubscriptionId();
+            if (!mPhoneStateListeners.containsKey(subId)) {
+                CallNotifierPhoneStateListener listener = new CallNotifierPhoneStateListener(subId);
+                mTelephonyManager.listen(listener,
+                        PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
+                        | PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR);
+                mPhoneStateListeners.put(subId, listener);
+            }
+        }
+    }
+
+    /**
+     * @return {@code true} if the list contains SubscriptionInfo with the given subscription id.
+     */
+    private boolean containsSubId(List<SubscriptionInfo> subInfos, int subId) {
+        if (subInfos == null) {
+            return false;
+        }
+
+        for (int i = 0; i < subInfos.size(); i++) {
+            if (subInfos.get(i).getSubscriptionId() == subId) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Helper class to play SignalInfo tones using the ToneGenerator.
      *
@@ -1014,14 +1079,32 @@
     }
 
     private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
-        new BluetoothProfile.ServiceListener() {
-        public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            mBluetoothHeadset = (BluetoothHeadset) proxy;
-            if (VDBG) log("- Got BluetoothHeadset: " + mBluetoothHeadset);
+           new BluetoothProfile.ServiceListener() {
+                public void onServiceConnected(int profile, BluetoothProfile proxy) {
+                    mBluetoothHeadset = (BluetoothHeadset) proxy;
+                    if (VDBG) log("- Got BluetoothHeadset: " + mBluetoothHeadset);
+                }
+
+                public void onServiceDisconnected(int profile) {
+                    mBluetoothHeadset = null;
+                }
+            };
+
+    private class CallNotifierPhoneStateListener extends PhoneStateListener {
+        public CallNotifierPhoneStateListener(int subId) {
+            super(subId);
         }
 
-        public void onServiceDisconnected(int profile) {
-            mBluetoothHeadset = null;
+        @Override
+        public void onMessageWaitingIndicatorChanged(boolean visible) {
+            if (VDBG) log("onMessageWaitingIndicatorChanged(): " + this.mSubId + " " + visible);
+            mApplication.notificationMgr.updateMwi(this.mSubId, visible);
+        }
+
+        @Override
+        public void onCallForwardingIndicatorChanged(boolean visible) {
+            if (VDBG) log("onCallForwardingIndicatorChanged(): " + this.mSubId + " " + visible);
+            mApplication.notificationMgr.updateCfi(this.mSubId, visible);
         }
     };
 
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index 106484b..60121d8 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -87,7 +87,6 @@
     private static final String LOG_TAG = "EmergencyDialer";
 
     private StatusBarManager mStatusBarManager;
-    private AccessibilityManager mAccessibilityManager;
 
     /** The length of DTMF tones in milliseconds */
     private static final int TONE_LENGTH_MS = 150;
@@ -161,7 +160,6 @@
         super.onCreate(icicle);
 
         mStatusBarManager = (StatusBarManager) getSystemService(Context.STATUS_BAR_SERVICE);
-        mAccessibilityManager = (AccessibilityManager) getSystemService(ACCESSIBILITY_SERVICE);
 
         // Allow this activity to be displayed in front of the keyguard / lockscreen.
         WindowManager.LayoutParams lp = getWindow().getAttributes();
@@ -180,10 +178,6 @@
         mDigits.setOnClickListener(this);
         mDigits.setOnKeyListener(this);
         mDigits.setLongClickable(false);
-        if (mAccessibilityManager.isEnabled()) {
-            // The text view must be selected to send accessibility events.
-            mDigits.setSelected(true);
-        }
         maybeAddNumberFormatting();
 
         // Check for the presence of the keypad
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index 0eb8374..efb61f6 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -601,14 +601,14 @@
                         return true;
                 }
 
-                UpdatePreferredNetworkModeSummary(buttonNetworkMode);
-
                 android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
                         android.provider.Settings.Global.PREFERRED_NETWORK_MODE + phoneSubId,
                         buttonNetworkMode );
                 //Set the modem network mode
                 mPhone.setPreferredNetworkType(modemNetworkMode, mHandler
                         .obtainMessage(MyHandler.MESSAGE_SET_PREFERRED_NETWORK_TYPE));
+
+                updateBody();
             }
         } else if (preference == mButtonEnabledNetworks) {
             mButtonEnabledNetworks.setValue((String) objValue);
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index 6e372c2..f026442 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -33,11 +33,15 @@
 import android.provider.ContactsContract.PhoneLookup;
 import android.provider.Settings;
 import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.ServiceState;
+import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
-import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.widget.Toast;
 
@@ -45,8 +49,12 @@
 import com.android.internal.telephony.PhoneBase;
 import com.android.internal.telephony.TelephonyCapabilities;
 import com.android.phone.settings.VoicemailNotificationSettingsUtil;
+import com.android.phone.settings.VoicemailProviderSettingsUtil;
 
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * NotificationManager-related utility code for the Phone app.
@@ -83,12 +91,18 @@
     private StatusBarManager mStatusBarManager;
     private UserManager mUserManager;
     private Toast mToast;
+    private SubscriptionManager mSubscriptionManager;
+    private TelecomManager mTelecomManager;
+    private TelephonyManager mTelephonyManager;
 
     public StatusBarHelper statusBarHelper;
 
     // used to track the notification of selected network unavailable
     private boolean mSelectedUnavailableNotify = false;
 
+    // used to track whether the message waiting indicator is visible, per subscription id.
+    private ArrayMap<Integer, Boolean> mMwiVisible = new ArrayMap<Integer, Boolean>();
+
     /**
      * Private constructor (this is a singleton).
      * @see #init(PhoneGlobals)
@@ -103,15 +117,9 @@
         mUserManager = (UserManager) app.getSystemService(Context.USER_SERVICE);
         mPhone = app.phone;  // TODO: better style to use mCM.getDefaultPhone() everywhere instead
         statusBarHelper = new StatusBarHelper();
-
-        SubscriptionManager.from(mContext).registerOnSubscriptionsChangedListener(
-                new OnSubscriptionsChangedListener() {
-                    @Override
-                    public void onSubscriptionsChanged() {
-                        // Update the message waiting indicator if the SIM is changed.
-                        updateMwi(mPhone.getMessageWaitingIndicator());
-                    }
-                });
+        mSubscriptionManager = SubscriptionManager.from(mContext);
+        mTelecomManager = TelecomManager.from(mContext);
+        mTelephonyManager = (TelephonyManager) app.getSystemService(Context.TELEPHONY_SERVICE);
     }
 
     /**
@@ -158,7 +166,7 @@
         private boolean mIsExpandedViewEnabled = true;
         private boolean mIsSystemBarNavigationEnabled = true;
 
-        private StatusBarHelper () {
+        private StatusBarHelper() {
         }
 
         /**
@@ -236,12 +244,52 @@
     };
 
     /**
+     * Re-creates the message waiting indicator (voicemail) notification if it is showing.  Used to
+     * refresh the voicemail intent on the indicator when the user changes it via the voicemail
+     * settings screen.  The voicemail notification sound is suppressed.
+     *
+     * @param subId The subscription Id.
+     */
+    /* package */ void refreshMwi(int subId) {
+        // In a single-sim device, subId can be -1 which means "no sub id".  In this case we will
+        // reference the single subid stored in the mMwiVisible map.
+        if (subId == SubscriptionInfoHelper.NO_SUB_ID) {
+            if (mMwiVisible.keySet().size() == 1) {
+                Set<Integer> keySet = mMwiVisible.keySet();
+                Iterator<Integer> keyIt = keySet.iterator();
+                if (!keyIt.hasNext()) {
+                    return;
+                }
+                subId = keyIt.next();
+            }
+        }
+        if (mMwiVisible.containsKey(subId)) {
+            boolean mwiVisible = mMwiVisible.get(subId);
+            if (mwiVisible) {
+                updateMwi(subId, mwiVisible, false /* enableNotificationSound */);
+            }
+        }
+    }
+
+    /**
      * Updates the message waiting indicator (voicemail) notification.
      *
      * @param visible true if there are messages waiting
      */
-    /* package */ void updateMwi(boolean visible) {
-        if (DBG) log("updateMwi(): " + visible);
+    /* package */ void updateMwi(int subId, boolean visible) {
+        updateMwi(subId, visible, true /* enableNotificationSound */);
+    }
+
+    /**
+     * Updates the message waiting indicator (voicemail) notification.
+     *
+     * @param subId the subId to update.
+     * @param visible true if there are messages waiting
+     * @param enableNotificationSound {@code true} if the notification sound should be played.
+     */
+    void updateMwi(int subId, boolean visible, boolean enableNotificationSound) {
+        if (DBG) log("updateMwi(): subId " + subId + " update to " + visible);
+        mMwiVisible.put(subId, visible);
 
         if (!PhoneGlobals.sVoiceCapable) {
             // Do not show the message waiting indicator on devices which are not voice capable.
@@ -251,6 +299,18 @@
         }
 
         if (visible) {
+            Phone phone = PhoneGlobals.getPhone(subId);
+            if (phone == null) {
+                Log.w(LOG_TAG, "Found null phone for: " + subId);
+                return;
+            }
+
+            SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId);
+            if (subInfo == null) {
+                Log.w(LOG_TAG, "Found null subscription info for: " + subId);
+                return;
+            }
+
             int resId = android.R.drawable.stat_notify_voicemail;
 
             // This Notification can get a lot fancier once we have more
@@ -264,7 +324,7 @@
             // notification.
 
             String notificationTitle = mContext.getString(R.string.notification_voicemail_title);
-            String vmNumber = mPhone.getVoiceMailNumber();
+            String vmNumber = phone.getVoiceMailNumber();
             if (DBG) log("- got vm number: '" + vmNumber + "'");
 
             // The voicemail number may be null because:
@@ -272,37 +332,61 @@
             //   (2) This phone has a voicemail number, but the SIM isn't ready yet. This may
             //       happen when the device first boots if we get a MWI notification when we
             //       register on the network before the SIM has loaded. In this case, the
-            //       SubscriptionListener this class registers on the SubscriptionManager will
-            //       call this method again once the SIM is loaded.
-            if ((vmNumber == null) && !mPhone.getIccRecordsLoaded()) {
+            //       SubscriptionListener in CallNotifier will update this once the SIM is loaded.
+            if ((vmNumber == null) && !phone.getIccRecordsLoaded()) {
                 if (DBG) log("- Null vm number: SIM records not loaded (yet)...");
                 return;
             }
 
-            if (TelephonyCapabilities.supportsVoiceMessageCount(mPhone)) {
-                int vmCount = mPhone.getVoiceMessageCount();
+            if (TelephonyCapabilities.supportsVoiceMessageCount(phone)) {
+                int vmCount = phone.getVoiceMessageCount();
                 String titleFormat = mContext.getString(R.string.notification_voicemail_title_count);
                 notificationTitle = String.format(titleFormat, vmCount);
             }
 
+            // This pathway only applies to PSTN accounts; only SIMS have subscription ids.
+            PhoneAccountHandle phoneAccountHandle = PhoneUtils.makePstnPhoneAccountHandle(phone);
+
+            Intent intent;
             String notificationText;
             if (TextUtils.isEmpty(vmNumber)) {
                 notificationText = mContext.getString(
                         R.string.notification_voicemail_no_vm_number);
+
+                // If the voicemail number if unknown, instead of calling voicemail, take the user
+                // to the voicemail settings.
+                notificationText = mContext.getString(
+                        R.string.notification_voicemail_no_vm_number);
+                intent = new Intent(CallFeaturesSetting.ACTION_ADD_VOICEMAIL);
+                intent.putExtra(CallFeaturesSetting.SETUP_VOICEMAIL_EXTRA, true);
+                intent.putExtra(SubscriptionInfoHelper.SUB_ID_EXTRA, subId);
+                intent.setClass(mContext, CallFeaturesSetting.class);
             } else {
-                notificationText = String.format(
-                        mContext.getString(R.string.notification_voicemail_text_format),
-                        PhoneNumberUtils.formatNumber(vmNumber));
+                if (mTelephonyManager.getPhoneCount() > 1) {
+                    notificationText = subInfo.getDisplayName().toString();
+                } else {
+                    notificationText = String.format(
+                            mContext.getString(R.string.notification_voicemail_text_format),
+                            PhoneNumberUtils.formatNumber(vmNumber));
+                }
+                intent = new Intent(
+                        Intent.ACTION_CALL, Uri.fromParts(PhoneAccount.SCHEME_VOICEMAIL, "",
+                        null));
+                intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
             }
 
-            Intent intent = new Intent(Intent.ACTION_CALL,
-                    Uri.fromParts(PhoneAccount.SCHEME_VOICEMAIL, "", null));
-            PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
-            Uri ringtoneUri = VoicemailNotificationSettingsUtil.getRingtoneUri(mPhone);
+            PendingIntent pendingIntent =
+                    PendingIntent.getActivity(mContext, subId /* requestCode */, intent, 0);
+            Uri ringtoneUri = null;
+
+            if (enableNotificationSound) {
+                ringtoneUri = VoicemailNotificationSettingsUtil.getRingtoneUri(mPhone);
+            }
 
             Notification.Builder builder = new Notification.Builder(mContext);
             builder.setSmallIcon(resId)
                     .setWhen(System.currentTimeMillis())
+                    .setColor(subInfo.getIconTint())
                     .setContentTitle(notificationTitle)
                     .setContentText(notificationText)
                     .setContentIntent(pendingIntent)
@@ -310,7 +394,7 @@
                     .setColor(mContext.getResources().getColor(R.color.dialer_theme_color))
                     .setOngoing(true);
 
-            if (VoicemailNotificationSettingsUtil.isVibrationEnabled(mPhone)) {
+            if (VoicemailNotificationSettingsUtil.isVibrationEnabled(phone)) {
                 builder.setDefaults(Notification.DEFAULT_VIBRATE);
             }
 
@@ -323,12 +407,17 @@
                         UserManager.DISALLOW_OUTGOING_CALLS, userHandle)
                             && !user.isManagedProfile()) {
                     mNotificationManager.notifyAsUser(
-                            null /* tag */, VOICEMAIL_NOTIFICATION, notification, userHandle);
+                            Integer.toString(subId) /* tag */,
+                            VOICEMAIL_NOTIFICATION,
+                            notification,
+                            userHandle);
                 }
             }
         } else {
             mNotificationManager.cancelAsUser(
-                    null /* tag */, VOICEMAIL_NOTIFICATION, UserHandle.ALL);
+                    Integer.toString(subId) /* tag */,
+                    VOICEMAIL_NOTIFICATION,
+                    UserHandle.ALL);
         }
     }
 
@@ -337,7 +426,7 @@
      *
      * @param visible true if there are messages waiting
      */
-    /* package */ void updateCfi(boolean visible) {
+    /* package */ void updateCfi(int subId, boolean visible) {
         if (DBG) log("updateCfi(): " + visible);
         if (visible) {
             // If Unconditional Call Forwarding (forward all calls) for VOICE
@@ -351,17 +440,34 @@
             // effort though, since there are multiple layers of messages that
             // will need to propagate that information.
 
+            SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId);
+            if (subInfo == null) {
+                Log.w(LOG_TAG, "Found null subscription info for: " + subId);
+                return;
+            }
+
+            String notificationTitle;
+            if (mTelephonyManager.getPhoneCount() > 1) {
+                notificationTitle = subInfo.getDisplayName().toString();
+            } else {
+                notificationTitle = mContext.getString(R.string.labelCF);
+            }
+
             Notification.Builder builder = new Notification.Builder(mContext)
                     .setSmallIcon(R.drawable.stat_sys_phone_call_forward)
-                    .setContentTitle(mContext.getString(R.string.labelCF))
+                    .setColor(subInfo.getIconTint())
+                    .setContentTitle(notificationTitle)
                     .setContentText(mContext.getString(R.string.sum_cfu_enabled_indicator))
                     .setShowWhen(false)
                     .setOngoing(true);
 
             Intent intent = new Intent(Intent.ACTION_MAIN);
-            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
             intent.setClassName("com.android.phone", "com.android.phone.CallFeaturesSetting");
-            PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
+            SubscriptionInfoHelper.addExtrasToIntent(
+                    intent, mSubscriptionManager.getActiveSubscriptionInfo(subId));
+            PendingIntent contentIntent =
+                    PendingIntent.getActivity(mContext, subId /* requestCode */, intent, 0);
 
             List<UserInfo> users = mUserManager.getUsers(true);
             for (int i = 0; i < users.size(); i++) {
@@ -371,12 +477,17 @@
                 }
                 UserHandle userHandle = user.getUserHandle();
                 builder.setContentIntent(userHandle.isOwner() ? contentIntent : null);
-                    mNotificationManager.notifyAsUser(
-                            null /* tag */, CALL_FORWARD_NOTIFICATION, builder.build(), userHandle);
+                mNotificationManager.notifyAsUser(
+                        Integer.toString(subId) /* tag */,
+                        CALL_FORWARD_NOTIFICATION,
+                        builder.build(),
+                        userHandle);
             }
         } else {
             mNotificationManager.cancelAsUser(
-                    null /* tag */, CALL_FORWARD_NOTIFICATION, UserHandle.ALL);
+                    Integer.toString(subId) /* tag */,
+                    CALL_FORWARD_NOTIFICATION,
+                    UserHandle.ALL);
         }
     }
 
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index fe40b17..2fcce90 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -48,6 +48,7 @@
 import android.preference.PreferenceManager;
 import android.provider.Settings.System;
 import android.telephony.ServiceState;
+import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.util.Log;
 
@@ -402,8 +403,7 @@
             // asynchronous events from the telephony layer (like
             // launching the incoming-call UI when an incoming call comes
             // in.)
-            notifier = CallNotifier.init(this, phone, callLogger, callStateMonitor,
-                    bluetoothManager);
+            notifier = CallNotifier.init(this, callLogger, callStateMonitor, bluetoothManager);
 
             // register for ICC status
             IccCard sim = phone.getIccCard();
@@ -492,17 +492,8 @@
         return getInstance().phone;
     }
 
-    /**
-     * Returns a list of the currently active phones for the Telephony package.
-     */
-    public static List<Phone> getPhones() {
-        int[] subIds = SubscriptionController.getInstance().getActiveSubIdList();
-        List<Phone> phones = new ArrayList<Phone>(subIds.length);
-
-        for (int i = 0; i < subIds.length; i++) {
-            phones.add(PhoneFactory.getPhone(SubscriptionManager.getPhoneId(subIds[i])));
-        }
-        return phones;
+    public static Phone getPhone(int subId) {
+        return PhoneFactory.getPhone(SubscriptionManager.getPhoneId(subId));
     }
 
     /* package */ BluetoothManager getBluetoothManager() {
@@ -933,6 +924,15 @@
     }
 
     /**
+     * Triggers a refresh of the message waiting (voicemail) indicator.
+     *
+     * @param subId the subscription id we should refresh the notification for.
+     */
+    public void refreshMwiIndicator(int subId) {
+        notificationMgr.refreshMwi(subId);
+    }
+
+    /**
      * "Call origin" may be used by Contacts app to specify where the phone call comes from.
      * Currently, the only permitted value for this extra is {@link #ALLOWED_EXTRA_CALL_ORIGIN}.
      * Any other value will be ignored, to make sure that malicious apps can't trick the in-call
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index d83f10d..d20df1b 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -41,10 +41,14 @@
 import android.telephony.RadioAccessFamily;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.Pair;
+import android.util.Slog;
 
 import com.android.ims.ImsManager;
 import com.android.internal.telephony.CallManager;
@@ -66,7 +70,10 @@
 import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 
 /**
  * Implementation of the ITelephony interface.
@@ -75,6 +82,7 @@
     private static final String LOG_TAG = "PhoneInterfaceManager";
     private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
     private static final boolean DBG_LOC = false;
+    private static final boolean DBG_MERGE = false;
 
     // Message codes used with mMainThreadHandler
     private static final int CMD_HANDLE_PIN_MMI = 1;
@@ -124,6 +132,7 @@
 
     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_SUBSCRIBER_PREFIX = "carrier_subscriber_";
     private static final String PREF_ENABLE_VIDEO_CALLING = "enable_video_calling";
 
     /**
@@ -1908,9 +1917,17 @@
      * @param enable {@code true} turn turn data on, else {@code false}
      */
     @Override
-    public void setDataEnabled(boolean enable) {
+    public void setDataEnabled(int subId, boolean enable) {
         enforceModifyPermission();
-        mPhone.setDataEnabled(enable);
+        int phoneId = mSubscriptionController.getPhoneId(subId);
+        log("getDataEnabled: subId=" + subId + " phoneId=" + phoneId);
+        Phone phone = PhoneFactory.getPhone(phoneId);
+        if (phone != null) {
+            log("setDataEnabled: subId=" + subId + " enable=" + enable);
+            phone.setDataEnabled(enable);
+        } else {
+            loge("setDataEnabled: no phone for subId=" + subId);
+        }
     }
 
     /**
@@ -1923,7 +1940,7 @@
      * @return {@code true} if data is enabled else {@code false}
      */
     @Override
-    public boolean getDataEnabled() {
+    public boolean getDataEnabled(int subId) {
         try {
             mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
                     null);
@@ -1931,7 +1948,17 @@
             mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
                     null);
         }
-        return mPhone.getDataEnabled();
+        int phoneId = mSubscriptionController.getPhoneId(subId);
+        log("getDataEnabled: subId=" + subId + " phoneId=" + phoneId);
+        Phone phone = PhoneFactory.getPhone(phoneId);
+        if (phone != null) {
+            boolean retVal = phone.getDataEnabled();
+            log("getDataEnabled: subId=" + subId + " retVal=" + retVal);
+            return retVal;
+        } else {
+            loge("getDataEnabled: no phone subId=" + subId + " retVal=false");
+            return false;
+        }
     }
 
     @Override
@@ -1981,28 +2008,43 @@
     }
 
     @Override
-    public boolean setLine1NumberForDisplayForSubscriber(int subId, String alphaTag, String number) {
+    public boolean setLine1NumberForDisplayForSubscriber(int subId, String alphaTag,
+            String number) {
         enforceCarrierPrivilege();
 
-        String iccId = getIccId(subId);
+        final String iccId = getIccId(subId);
+        final String subscriberId = getPhone(subId).getSubscriberId();
+
+        if (DBG_MERGE) {
+            Slog.d(LOG_TAG, "Setting line number for ICC=" + iccId + ", subscriberId="
+                    + subscriberId + " to " + number);
+        }
+
         if (TextUtils.isEmpty(iccId)) {
             return false;
         }
 
-        String alphaTagPrefKey = PREF_CARRIERS_ALPHATAG_PREFIX + iccId;
-        SharedPreferences.Editor editor = mTelephonySharedPreferences.edit();
+        final SharedPreferences.Editor editor = mTelephonySharedPreferences.edit();
+
+        final String alphaTagPrefKey = PREF_CARRIERS_ALPHATAG_PREFIX + iccId;
         if (alphaTag == null) {
             editor.remove(alphaTagPrefKey);
         } else {
             editor.putString(alphaTagPrefKey, alphaTag);
         }
 
-        String numberPrefKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
+        // Record both the line number and IMSI for this ICCID, since we need to
+        // track all merged IMSIs based on line number
+        final String numberPrefKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
+        final String subscriberPrefKey = PREF_CARRIERS_SUBSCRIBER_PREFIX + iccId;
         if (number == null) {
             editor.remove(numberPrefKey);
+            editor.remove(subscriberPrefKey);
         } else {
             editor.putString(numberPrefKey, number);
+            editor.putString(subscriberPrefKey, subscriberId);
         }
+
         editor.commit();
         return true;
     }
@@ -2032,6 +2074,69 @@
     }
 
     @Override
+    public String[] getMergedSubscriberIds() {
+        final Context context = mPhone.getContext();
+        final TelephonyManager tele = TelephonyManager.from(context);
+        final SubscriptionManager sub = SubscriptionManager.from(context);
+
+        // Figure out what subscribers are currently active
+        final ArraySet<String> activeSubscriberIds = new ArraySet<>();
+        final int[] subIds = sub.getActiveSubscriptionIdList();
+        for (int subId : subIds) {
+            activeSubscriberIds.add(tele.getSubscriberId(subId));
+        }
+
+        // First pass, find a number override for an active subscriber
+        String mergeNumber = null;
+        final Map<String, ?> prefs = mTelephonySharedPreferences.getAll();
+        for (String key : prefs.keySet()) {
+            if (key.startsWith(PREF_CARRIERS_SUBSCRIBER_PREFIX)) {
+                final String subscriberId = (String) prefs.get(key);
+                if (activeSubscriberIds.contains(subscriberId)) {
+                    final String iccId = key.substring(PREF_CARRIERS_SUBSCRIBER_PREFIX.length());
+                    final String numberKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
+                    mergeNumber = (String) prefs.get(numberKey);
+                    if (DBG_MERGE) {
+                        Slog.d(LOG_TAG, "Found line number " + mergeNumber
+                                + " for active subscriber " + subscriberId);
+                    }
+                    if (!TextUtils.isEmpty(mergeNumber)) {
+                        break;
+                    }
+                }
+            }
+        }
+
+        // Shortcut when no active merged subscribers
+        if (TextUtils.isEmpty(mergeNumber)) {
+            return null;
+        }
+
+        // Second pass, find all subscribers under that line override
+        final ArraySet<String> result = new ArraySet<>();
+        for (String key : prefs.keySet()) {
+            if (key.startsWith(PREF_CARRIERS_NUMBER_PREFIX)) {
+                final String number = (String) prefs.get(key);
+                if (mergeNumber.equals(number)) {
+                    final String iccId = key.substring(PREF_CARRIERS_NUMBER_PREFIX.length());
+                    final String subscriberKey = PREF_CARRIERS_SUBSCRIBER_PREFIX + iccId;
+                    final String subscriberId = (String) prefs.get(subscriberKey);
+                    if (!TextUtils.isEmpty(subscriberId)) {
+                        result.add(subscriberId);
+                    }
+                }
+            }
+        }
+
+        final String[] resultArray = result.toArray(new String[result.size()]);
+        Arrays.sort(resultArray);
+        if (DBG_MERGE) {
+            Slog.d(LOG_TAG, "Found subscribers " + Arrays.toString(resultArray) + " after merge");
+        }
+        return resultArray;
+    }
+
+    @Override
     public boolean setOperatorBrandOverride(String brand) {
         enforceCarrierPrivilege();
         return mPhone.setOperatorBrandOverride(brand);
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index b3d64db..0c8b62c 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -33,6 +33,7 @@
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
 import android.telecom.VideoProfile;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
@@ -57,6 +58,7 @@
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.sip.SipPhone;
 import com.android.phone.CallGatewayManager.RawGatewayInfo;
+import com.android.services.telephony.TelephonyConnectionService;
 
 import java.util.Arrays;
 import java.util.List;
@@ -2434,4 +2436,18 @@
         return context.getResources().getConfiguration().orientation
                 == Configuration.ORIENTATION_LANDSCAPE;
     }
+
+    public static PhoneAccountHandle makePstnPhoneAccountHandle(Phone phone) {
+        return makePstnPhoneAccountHandleWithPrefix(phone, "", false);
+    }
+
+    public static PhoneAccountHandle makePstnPhoneAccountHandleWithPrefix(
+            Phone phone, String prefix, boolean isEmergency) {
+        ComponentName pstnConnectionServiceName =
+                new ComponentName(phone.getContext(), TelephonyConnectionService.class);
+        // TODO: Should use some sort of special hidden flag to decorate this account as
+        // an emergency-only account
+        String id = isEmergency ? "E" : prefix + String.valueOf(phone.getSubId());
+        return new PhoneAccountHandle(pstnConnectionServiceName, id);
+    }
 }
diff --git a/src/com/android/phone/SubscriptionInfoHelper.java b/src/com/android/phone/SubscriptionInfoHelper.java
index 1255452..f325b1a 100644
--- a/src/com/android/phone/SubscriptionInfoHelper.java
+++ b/src/com/android/phone/SubscriptionInfoHelper.java
@@ -36,10 +36,10 @@
  * helping extract this info and perform common operations using this info.
  */
 public class SubscriptionInfoHelper {
-    private static final int NO_SUB_ID = -1;
+    public static final int NO_SUB_ID = -1;
 
     // Extra on intent containing the id of a subscription.
-    private static final String SUB_ID_EXTRA =
+    public static final String SUB_ID_EXTRA =
             "com.android.phone.settings.SubscriptionInfoHelper.SubscriptionId";
     // Extra on intent containing the label of a subscription.
     private static final String SUB_LABEL_EXTRA =
@@ -76,6 +76,10 @@
     }
 
     public static void addExtrasToIntent(Intent intent, SubscriptionInfo subscription) {
+        if (subscription == null) {
+            return;
+        }
+
         intent.putExtra(SubscriptionInfoHelper.SUB_ID_EXTRA, subscription.getSubscriptionId());
         intent.putExtra(
                 SubscriptionInfoHelper.SUB_LABEL_EXTRA, subscription.getDisplayName().toString());
diff --git a/src/com/android/phone/settings/PhoneAccountSettingsFragment.java b/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
index 03374ce..83fa5da 100644
--- a/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
+++ b/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
@@ -11,7 +11,6 @@
 import android.preference.Preference;
 import android.preference.PreferenceCategory;
 import android.preference.PreferenceFragment;
-import android.preference.SwitchPreference;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.telephony.SubscriptionInfo;
@@ -43,8 +42,6 @@
             "phone_accounts_call_assistant_settings_category_key";
     private static final String SELECT_CALL_ASSISTANT_PREF_KEY =
             "wifi_calling_call_assistant_preference";
-    private static final String SELECT_CALL_ASSISTANT_SWITCH_KEY =
-            "wifi_calling_call_assistant_switch";
 
     private static final String SIP_SETTINGS_CATEGORY_PREF_KEY =
             "phone_accounts_sip_settings_category_key";
@@ -60,7 +57,6 @@
 
     private AccountSelectionPreference mDefaultOutgoingAccount;
     private AccountSelectionPreference mSelectCallAssistant;
-    private SwitchPreference mCallAssistantSwitch;
     private Preference mConfigureCallAssistant;
 
     private ListPreference mUseSipCalling;
@@ -110,33 +106,14 @@
         if (simCallManagers.isEmpty()) {
             getPreferenceScreen().removePreference(callAssistantCategory);
         } else {
-            if (simCallManagers.size() == 1) {
-                // If there's only a single call assistant then display an ON/OFF switch. Turning
-                // the switch on enables the call assistant and turning it off disables it.
-                callAssistantCategory.removePreference(
-                        getPreferenceScreen().findPreference(SELECT_CALL_ASSISTANT_PREF_KEY));
-                CharSequence title =
-                    mTelecomManager.getPhoneAccount(simCallManagers.get(0)).getLabel();
-                callAssistantCategory.setTitle(title);
-                mCallAssistantSwitch = (SwitchPreference)
-                        getPreferenceScreen().findPreference(SELECT_CALL_ASSISTANT_SWITCH_KEY);
-                mCallAssistantSwitch.setTitle(title);
-                mCallAssistantSwitch.setChecked(simCallManagers.get(0).equals(
-                        mTelecomManager.getSimCallManager()));
-                mCallAssistantSwitch.setOnPreferenceChangeListener(this);
-                mCallAssistantSwitch.setEnabled(true);
-            } else {
-                // If there's more than one call assistant then display a list. Choosing an item
-                // from the list enables the corresponding call assistant.
-                callAssistantCategory.removePreference(
-                        getPreferenceScreen().findPreference(SELECT_CALL_ASSISTANT_SWITCH_KEY));
-                mSelectCallAssistant = (AccountSelectionPreference)
-                        getPreferenceScreen().findPreference(SELECT_CALL_ASSISTANT_PREF_KEY);
-                mSelectCallAssistant.setListener(this);
-                mSelectCallAssistant.setDialogTitle(
-                        R.string.wifi_calling_select_call_assistant_summary);
-                updateCallAssistantModel();
-            }
+            // Display a list of call assistants. Choosing an item from the list enables the
+            // corresponding call assistant.
+            mSelectCallAssistant = (AccountSelectionPreference)
+                    getPreferenceScreen().findPreference(SELECT_CALL_ASSISTANT_PREF_KEY);
+            mSelectCallAssistant.setListener(this);
+            mSelectCallAssistant.setDialogTitle(
+                    R.string.wifi_calling_select_call_assistant_summary);
+            updateCallAssistantModel();
 
             mConfigureCallAssistant =
                     getPreferenceScreen().findPreference(CONFIGURE_CALL_ASSISTANT_PREF_KEY);
@@ -201,20 +178,6 @@
                 }
             }).start();
             return true;
-        } else if (pref == mCallAssistantSwitch) {
-            List<PhoneAccountHandle> simCallManagers = mTelecomManager.getSimCallManagers();
-            if (simCallManagers.size() == 1) {
-                if (Boolean.TRUE.equals(objValue)) {
-                    mTelecomManager.setSimCallManager(simCallManagers.get(0));
-                } else {
-                    mTelecomManager.setSimCallManager(null);
-                }
-                updateConfigureCallAssistant();
-            } else {
-                Log.w(LOG_TAG, "Single call assistant expected but " + simCallManagers.size()
-                    + " found. Ignoring preference change.");
-            }
-            return true;
         }
         return false;
     }
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index 2870481..528b65d 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -16,17 +16,18 @@
 
 package com.android.services.telephony;
 
+import android.net.Uri;
+import android.telecom.Conference;
+import android.telecom.ConferenceParticipant;
+import android.telecom.Connection;
+import android.telecom.DisconnectCause;
+import android.telecom.PhoneAccountHandle;
+
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.imsphone.ImsPhoneConnection;
-
-import android.net.Uri;
-import android.telecom.Connection;
-import android.telecom.Conference;
-import android.telecom.ConferenceParticipant;
-import android.telecom.DisconnectCause;
-import android.telecom.PhoneAccountHandle;
+import com.android.phone.PhoneUtils;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -37,7 +38,7 @@
 
 /**
  * Represents an IMS conference call.
- * <P>
+ * <p>
  * An IMS conference call consists of a conference host connection and potentially a list of
  * conference participants.  The conference host connection represents the radio connection to the
  * IMS conference server.  Since it is not a connection to any one individual, it is not represented
@@ -432,7 +433,7 @@
 
         mConferenceParticipantConnections.put(participant.getEndpoint(), connection);
         PhoneAccountHandle phoneAccountHandle =
-                TelecomAccountRegistry.makePstnPhoneAccountHandle(parent.getPhone());
+                PhoneUtils.makePstnPhoneAccountHandle(parent.getPhone());
         mTelephonyConnectionService.addExistingConnection(phoneAccountHandle, connection);
         addConnection(connection);
     }
@@ -496,7 +497,7 @@
             }
 
             PhoneAccountHandle phoneAccountHandle =
-                    TelecomAccountRegistry.makePstnPhoneAccountHandle(mConferenceHost.getPhone());
+                    PhoneUtils.makePstnPhoneAccountHandle(mConferenceHost.getPhone());
             mTelephonyConnectionService.addExistingConnection(phoneAccountHandle, mConferenceHost);
             mConferenceHost.removeConnectionListener(mConferenceHostListener);
             mConferenceHost.removeTelephonyConnectionListener(mTelephonyConnectionListener);
diff --git a/src/com/android/services/telephony/PstnIncomingCallNotifier.java b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
index f4c8a22..75f472b 100644
--- a/src/com/android/services/telephony/PstnIncomingCallNotifier.java
+++ b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
@@ -39,6 +39,7 @@
 import com.android.internal.telephony.PhoneProxy;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
+import com.android.phone.PhoneUtils;
 
 import com.google.common.base.Preconditions;
 
@@ -219,7 +220,7 @@
             extras.putParcelable(TelecomManager.EXTRA_UNKNOWN_CALL_HANDLE, uri);
         }
         TelecomManager.from(mPhoneProxy.getContext()).addNewUnknownCall(
-                TelecomAccountRegistry.makePstnPhoneAccountHandle(mPhoneProxy), extras);
+                PhoneUtils.makePstnPhoneAccountHandle(mPhoneProxy), extras);
     }
 
     /**
@@ -234,6 +235,6 @@
             extras.putParcelable(TelephonyManager.EXTRA_INCOMING_NUMBER, uri);
         }
         TelecomManager.from(mPhoneProxy.getContext()).addNewIncomingCall(
-                TelecomAccountRegistry.makePstnPhoneAccountHandle(mPhoneProxy), extras);
+                PhoneUtils.makePstnPhoneAccountHandle(mPhoneProxy), extras);
     }
 }
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 13b3c94..37e8147 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -35,6 +35,7 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.PhoneProxy;
+import com.android.phone.PhoneUtils;
 import com.android.phone.R;
 
 import java.util.Arrays;
@@ -77,7 +78,8 @@
 
             // Build the Phone account handle.
             PhoneAccountHandle phoneAccountHandle =
-                    makePstnPhoneAccountHandleWithPrefix(mPhone, dummyPrefix, isEmergency);
+                    PhoneUtils.makePstnPhoneAccountHandleWithPrefix(
+                            mPhone, dummyPrefix, isEmergency);
 
             // Populate the phone account data.
             int subId = mPhone.getSubId();
@@ -234,21 +236,6 @@
         // because this could signal a removal or addition of a SIM in a single SIM phone.
         mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
     }
-
-    static PhoneAccountHandle makePstnPhoneAccountHandle(Phone phone) {
-        return makePstnPhoneAccountHandleWithPrefix(phone, "", false);
-    }
-
-    private static PhoneAccountHandle makePstnPhoneAccountHandleWithPrefix(
-            Phone phone, String prefix, boolean isEmergency) {
-        ComponentName pstnConnectionServiceName =
-                new ComponentName(phone.getContext(), TelephonyConnectionService.class);
-        // TODO: Should use some sort of special hidden flag to decorate this account as
-        // an emergency-only account
-        String id = isEmergency ? "E" : prefix + String.valueOf(phone.getSubId());
-        return new PhoneAccountHandle(pstnConnectionServiceName, id);
-    }
-
     /**
      * Determines if the list of {@link AccountEntry}(s) contains an {@link AccountEntry} with a
      * specified {@link PhoneAccountHandle}.