Merge "Prevent adding a new CDMA call if know it will fail." into nyc-dev
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 43d9379..c056141 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.os.AsyncResult;
@@ -242,7 +243,7 @@
             MainThreadRequest request;
             Message onCompleted;
             AsyncResult ar;
-            UiccCard uiccCard = UiccController.getInstance().getUiccCard(mPhone.getPhoneId());
+            UiccCard uiccCard;
             IccAPDUArgument iccArgument;
 
             switch (msg.what) {
@@ -318,6 +319,7 @@
                 case CMD_TRANSMIT_APDU_LOGICAL_CHANNEL:
                     request = (MainThreadRequest) msg.obj;
                     iccArgument = (IccAPDUArgument) request.argument;
+                    uiccCard = getUiccCardFromRequest(request);
                     if (uiccCard == null) {
                         loge("iccTransmitApduLogicalChannel: No UICC");
                         request.result = new IccIoResult(0x6F, 0, (byte[])null);
@@ -358,6 +360,7 @@
                 case CMD_TRANSMIT_APDU_BASIC_CHANNEL:
                     request = (MainThreadRequest) msg.obj;
                     iccArgument = (IccAPDUArgument) request.argument;
+                    uiccCard = getUiccCardFromRequest(request);
                     if (uiccCard == null) {
                         loge("iccTransmitApduBasicChannel: No UICC");
                         request.result = new IccIoResult(0x6F, 0, (byte[])null);
@@ -397,6 +400,7 @@
                 case CMD_EXCHANGE_SIM_IO:
                     request = (MainThreadRequest) msg.obj;
                     iccArgument = (IccAPDUArgument) request.argument;
+                    uiccCard = getUiccCardFromRequest(request);
                     if (uiccCard == null) {
                         loge("iccExchangeSimIO: No UICC");
                         request.result = new IccIoResult(0x6F, 0, (byte[])null);
@@ -427,6 +431,7 @@
 
                 case CMD_SEND_ENVELOPE:
                     request = (MainThreadRequest) msg.obj;
+                    uiccCard = getUiccCardFromRequest(request);
                     if (uiccCard == null) {
                         loge("sendEnvelopeWithStatus: No UICC");
                         request.result = new IccIoResult(0x6F, 0, (byte[])null);
@@ -462,6 +467,7 @@
 
                 case CMD_OPEN_CHANNEL:
                     request = (MainThreadRequest) msg.obj;
+                    uiccCard = getUiccCardFromRequest(request);
                     if (uiccCard == null) {
                         loge("iccOpenLogicalChannel: No UICC");
                         request.result = new IccOpenLogicalChannelResponse(-1,
@@ -520,6 +526,7 @@
 
                 case CMD_CLOSE_CHANNEL:
                     request = (MainThreadRequest) msg.obj;
+                    uiccCard = getUiccCardFromRequest(request);
                     if (uiccCard == null) {
                         loge("iccCloseLogicalChannel: No UICC");
                         request.result = new IccIoResult(0x6F, 0, (byte[])null);
@@ -875,6 +882,12 @@
                 ? mPhone : getPhone(request.subId);
     }
 
+    private UiccCard getUiccCardFromRequest(MainThreadRequest request) {
+        Phone phone = getPhoneFromRequest(request);
+        return phone == null ? null :
+                UiccController.getInstance().getUiccCard(phone.getPhoneId());
+    }
+
     // returns phone associated with the subId.
     private Phone getPhone(int subId) {
         return PhoneFactory.getPhone(mSubscriptionController.getPhoneId(subId));
@@ -1597,7 +1610,7 @@
      *
      * @throws SecurityException if the caller does not have the required permission/privilege
      */
-    private void enforceModifyPermissionOrCarrierPrivilege() {
+    private void enforceModifyPermissionOrCarrierPrivilege(int subId) {
         int permission = mApp.checkCallingOrSelfPermission(
                 android.Manifest.permission.MODIFY_PHONE_STATE);
         if (permission == PackageManager.PERMISSION_GRANTED) {
@@ -1605,10 +1618,7 @@
         }
 
         log("No modify permission, check carrier privilege next.");
-        if (getCarrierPrivilegeStatus() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
-            loge("No Carrier Privilege.");
-            throw new SecurityException("No modify permission or carrier privilege.");
-        }
+        enforceCarrierPrivilege(subId);
     }
 
     /**
@@ -1616,8 +1626,9 @@
      *
      * @throws SecurityException if the caller does not have the required permission
      */
-    private void enforceCarrierPrivilege() {
-        if (getCarrierPrivilegeStatus() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+    private void enforceCarrierPrivilege(int subId) {
+        if (getCarrierPrivilegeStatus(subId) !=
+                    TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
             loge("No Carrier Privilege.");
             throw new SecurityException("No Carrier Privilege.");
         }
@@ -1743,7 +1754,7 @@
      */
     @Override
     public String getCdmaMdn(int subId) {
-        enforceModifyPermissionOrCarrierPrivilege();
+        enforceModifyPermissionOrCarrierPrivilege(subId);
         final Phone phone = getPhone(subId);
         if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA && phone != null) {
             return phone.getLine1Number();
@@ -1757,7 +1768,7 @@
      */
     @Override
     public String getCdmaMin(int subId) {
-        enforceModifyPermissionOrCarrierPrivilege();
+        enforceModifyPermissionOrCarrierPrivilege(subId);
         final Phone phone = getPhone(subId);
         if (phone != null && phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
             return phone.getCdmaMin();
@@ -1778,7 +1789,7 @@
      */
     @Override
     public boolean setVoiceMailNumber(int subId, String alphaTag, String number) {
-        enforceCarrierPrivilege();
+        enforceCarrierPrivilege(subId);
         Boolean success = (Boolean) sendRequest(CMD_SET_VOICEMAIL_NUMBER,
                 new Pair<String, String>(alphaTag, number), new Integer(subId));
         return success;
@@ -1968,37 +1979,37 @@
     }
 
     @Override
-    public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID) {
-        enforceModifyPermissionOrCarrierPrivilege();
+    public IccOpenLogicalChannelResponse iccOpenLogicalChannel(int subId, String AID) {
+        enforceModifyPermissionOrCarrierPrivilege(subId);
 
-        if (DBG) log("iccOpenLogicalChannel: " + AID);
+        if (DBG) log("iccOpenLogicalChannel: subId=" + subId + " aid=" + AID);
         IccOpenLogicalChannelResponse response = (IccOpenLogicalChannelResponse)sendRequest(
-            CMD_OPEN_CHANNEL, AID);
+            CMD_OPEN_CHANNEL, AID, subId);
         if (DBG) log("iccOpenLogicalChannel: " + response);
         return response;
     }
 
     @Override
-    public boolean iccCloseLogicalChannel(int channel) {
-        enforceModifyPermissionOrCarrierPrivilege();
+    public boolean iccCloseLogicalChannel(int subId, int channel) {
+        enforceModifyPermissionOrCarrierPrivilege(subId);
 
-        if (DBG) log("iccCloseLogicalChannel: " + channel);
+        if (DBG) log("iccCloseLogicalChannel: subId=" + subId + " chnl=" + channel);
         if (channel < 0) {
           return false;
         }
-        Boolean success = (Boolean)sendRequest(CMD_CLOSE_CHANNEL, channel);
+        Boolean success = (Boolean)sendRequest(CMD_CLOSE_CHANNEL, channel, subId);
         if (DBG) log("iccCloseLogicalChannel: " + success);
         return success;
     }
 
     @Override
-    public String iccTransmitApduLogicalChannel(int channel, int cla,
+    public String iccTransmitApduLogicalChannel(int subId, int channel, int cla,
             int command, int p1, int p2, int p3, String data) {
-        enforceModifyPermissionOrCarrierPrivilege();
+        enforceModifyPermissionOrCarrierPrivilege(subId);
 
         if (DBG) {
-            log("iccTransmitApduLogicalChannel: chnl=" + channel + " cla=" + cla +
-                    " cmd=" + command + " p1=" + p1 + " p2=" + p2 + " p3=" + p3 +
+            log("iccTransmitApduLogicalChannel: subId=" + subId + " chnl=" + channel +
+                    " cla=" + cla + " cmd=" + command + " p1=" + p1 + " p2=" + p2 + " p3=" + p3 +
                     " data=" + data);
         }
 
@@ -2007,7 +2018,7 @@
         }
 
         IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU_LOGICAL_CHANNEL,
-                new IccAPDUArgument(channel, cla, command, p1, p2, p3, data));
+                new IccAPDUArgument(channel, cla, command, p1, p2, p3, data), subId);
         if (DBG) log("iccTransmitApduLogicalChannel: " + response);
 
         // Append the returned status code to the end of the response payload.
@@ -2020,17 +2031,17 @@
     }
 
     @Override
-    public String iccTransmitApduBasicChannel(int cla, int command, int p1, int p2,
+    public String iccTransmitApduBasicChannel(int subId, int cla, int command, int p1, int p2,
                 int p3, String data) {
-        enforceModifyPermissionOrCarrierPrivilege();
+        enforceModifyPermissionOrCarrierPrivilege(subId);
 
         if (DBG) {
-            log("iccTransmitApduBasicChannel: cla=" + cla + " cmd=" + command + " p1="
-                    + p1 + " p2=" + p2 + " p3=" + p3 + " data=" + data);
+            log("iccTransmitApduBasicChannel: subId=" + subId + " cla=" + cla + " cmd=" + command
+                    + " p1=" + p1 + " p2=" + p2 + " p3=" + p3 + " data=" + data);
         }
 
         IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU_BASIC_CHANNEL,
-                new IccAPDUArgument(0, cla, command, p1, p2, p3, data));
+                new IccAPDUArgument(0, cla, command, p1, p2, p3, data), subId);
         if (DBG) log("iccTransmitApduBasicChannel: " + response);
 
         // Append the returned status code to the end of the response payload.
@@ -2043,18 +2054,19 @@
     }
 
     @Override
-    public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
+    public byte[] iccExchangeSimIO(int subId, int fileID, int command, int p1, int p2, int p3,
             String filePath) {
-        enforceModifyPermissionOrCarrierPrivilege();
+        enforceModifyPermissionOrCarrierPrivilege(subId);
 
         if (DBG) {
-            log("Exchange SIM_IO " + fileID + ":" + command + " " +
+            log("Exchange SIM_IO " + subId + ":" + fileID + ":" + command + " " +
                 p1 + " " + p2 + " " + p3 + ":" + filePath);
         }
 
         IccIoResult response =
             (IccIoResult)sendRequest(CMD_EXCHANGE_SIM_IO,
-                    new IccAPDUArgument(-1, fileID, command, p1, p2, p3, filePath));
+                    new IccAPDUArgument(-1, fileID, command, p1, p2, p3, filePath),
+                    subId);
 
         if (DBG) {
           log("Exchange SIM_IO [R]" + response);
@@ -2076,10 +2088,10 @@
     }
 
     @Override
-    public String sendEnvelopeWithStatus(String content) {
-        enforceModifyPermissionOrCarrierPrivilege();
+    public String sendEnvelopeWithStatus(int subId, String content) {
+        enforceModifyPermissionOrCarrierPrivilege(subId);
 
-        IccIoResult response = (IccIoResult)sendRequest(CMD_SEND_ENVELOPE, content);
+        IccIoResult response = (IccIoResult)sendRequest(CMD_SEND_ENVELOPE, content, subId);
         if (response.payload == null) {
           return "";
         }
@@ -2100,7 +2112,7 @@
      */
     @Override
     public String nvReadItem(int itemID) {
-        enforceModifyPermissionOrCarrierPrivilege();
+        enforceModifyPermissionOrCarrierPrivilege(getDefaultSubscription());
         if (DBG) log("nvReadItem: item " + itemID);
         String value = (String) sendRequest(CMD_NV_READ_ITEM, itemID);
         if (DBG) log("nvReadItem: item " + itemID + " is \"" + value + '"');
@@ -2117,7 +2129,7 @@
      */
     @Override
     public boolean nvWriteItem(int itemID, String itemValue) {
-        enforceModifyPermissionOrCarrierPrivilege();
+        enforceModifyPermissionOrCarrierPrivilege(getDefaultSubscription());
         if (DBG) log("nvWriteItem: item " + itemID + " value \"" + itemValue + '"');
         Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_ITEM,
                 new Pair<Integer, String>(itemID, itemValue));
@@ -2134,7 +2146,7 @@
      */
     @Override
     public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) {
-        enforceModifyPermissionOrCarrierPrivilege();
+        enforceModifyPermissionOrCarrierPrivilege(getDefaultSubscription());
         if (DBG) log("nvWriteCdmaPrl: value: " + HexDump.toHexString(preferredRoamingList));
         Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_CDMA_PRL, preferredRoamingList);
         if (DBG) log("nvWriteCdmaPrl: " + (success ? "ok" : "fail"));
@@ -2150,7 +2162,7 @@
      */
     @Override
     public boolean nvResetConfig(int resetType) {
-        enforceModifyPermissionOrCarrierPrivilege();
+        enforceModifyPermissionOrCarrierPrivilege(getDefaultSubscription());
         if (DBG) log("nvResetConfig: type " + resetType);
         Boolean success = (Boolean) sendRequest(CMD_NV_RESET_CONFIG, resetType);
         if (DBG) log("nvResetConfig: type " + resetType + ' ' + (success ? "ok" : "fail"));
@@ -2186,7 +2198,7 @@
      */
     @Override
     public void setNetworkSelectionModeAutomatic(int subId) {
-        enforceModifyPermissionOrCarrierPrivilege();
+        enforceModifyPermissionOrCarrierPrivilege(subId);
         if (DBG) log("setNetworkSelectionModeAutomatic: subId " + subId);
         sendRequest(CMD_SET_NETWORK_SELECTION_MODE_AUTOMATIC, null, subId);
     }
@@ -2197,7 +2209,7 @@
     @Override
     public boolean setNetworkSelectionModeManual(int subId, OperatorInfo operator,
             boolean persistSelection) {
-        enforceModifyPermissionOrCarrierPrivilege();
+        enforceModifyPermissionOrCarrierPrivilege(subId);
         if (DBG) log("setNetworkSelectionModeManual: subId:" + subId + " operator:" + operator);
         ManualNetworkSelectionArgument arg = new ManualNetworkSelectionArgument(operator,
                 persistSelection);
@@ -2209,7 +2221,7 @@
      */
     @Override
     public CellNetworkScanResult getCellNetworkScanResults(int subId) {
-        enforceModifyPermissionOrCarrierPrivilege();
+        enforceModifyPermissionOrCarrierPrivilege(subId);
         if (DBG) log("getCellNetworkScanResults: subId " + subId);
         CellNetworkScanResult result = (CellNetworkScanResult) sendRequest(
                 CMD_PERFORM_NETWORK_SCAN, null, subId);
@@ -2239,7 +2251,7 @@
      */
     @Override
     public int getPreferredNetworkType(int subId) {
-        enforceModifyPermissionOrCarrierPrivilege();
+        enforceModifyPermissionOrCarrierPrivilege(subId);
         if (DBG) log("getPreferredNetworkType");
         int[] result = (int[]) sendRequest(CMD_GET_PREFERRED_NETWORK_TYPE, null, subId);
         int networkType = (result != null ? result[0] : -1);
@@ -2256,7 +2268,7 @@
      */
     @Override
     public boolean setPreferredNetworkType(int subId, int networkType) {
-        enforceModifyPermissionOrCarrierPrivilege();
+        enforceModifyPermissionOrCarrierPrivilege(subId);
         if (DBG) log("setPreferredNetworkType: subId " + subId + " type " + networkType);
         Boolean success = (Boolean) sendRequest(CMD_SET_PREFERRED_NETWORK_TYPE, networkType, subId);
         if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
@@ -2277,7 +2289,7 @@
      */
     @Override
     public int getTetherApnRequired() {
-        enforceModifyPermissionOrCarrierPrivilege();
+        enforceModifyPermission();
         int dunRequired = Settings.Global.getInt(mPhone.getContext().getContentResolver(),
                 Settings.Global.TETHER_DUN_REQUIRED, 2);
         // If not set, check net.tethering.noprovisioning, TETHER_DUN_APN setting and
@@ -2340,14 +2352,19 @@
     }
 
     @Override
-    public int getCarrierPrivilegeStatus() {
-        UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId());
+    public int getCarrierPrivilegeStatus(int subId) {
+        final Phone phone = getPhone(subId);
+        if (phone == null) {
+            loge("getCarrierPrivilegeStatus: Invalid subId");
+            return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
+        }
+        UiccCard card = UiccController.getInstance().getUiccCard(phone.getPhoneId());
         if (card == null) {
             loge("getCarrierPrivilegeStatus: No UICC");
             return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
         }
         return card.getCarrierPrivilegeStatusForCurrentTransaction(
-                mPhone.getContext().getPackageManager());
+                phone.getContext().getPackageManager());
     }
 
     @Override
@@ -2395,6 +2412,38 @@
                 mPhone.getContext().getPackageManager(), intent);
     }
 
+    @Override
+    public List<String> getPackagesWithCarrierPrivileges() {
+        PackageManager pm = mPhone.getContext().getPackageManager();
+        List<String> privilegedPackages = new ArrayList<>();
+        List<PackageInfo> packages = null;
+        for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
+            UiccCard card = UiccController.getInstance().getUiccCard(i);
+            if (card == null) {
+                // No UICC in that slot.
+                continue;
+            }
+            if (card.hasCarrierPrivilegeRules()) {
+                if (packages == null) {
+                    // Only check packages in user 0 for now
+                    packages = pm.getInstalledPackagesAsUser(
+                            PackageManager.MATCH_DISABLED_COMPONENTS
+                            | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+                            | PackageManager.GET_SIGNATURES, UserHandle.USER_SYSTEM);
+                }
+                for (int p = packages.size() - 1; p >= 0; p--) {
+                    PackageInfo pkgInfo = packages.get(p);
+                    if (pkgInfo != null && pkgInfo.packageName != null
+                            && card.getCarrierPrivilegeStatus(pkgInfo)
+                                == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+                        privilegedPackages.add(pkgInfo.packageName);
+                    }
+                }
+            }
+        }
+        return privilegedPackages;
+    }
+
     private String getIccId(int subId) {
         final Phone phone = getPhone(subId);
         UiccCard card = phone == null ? null : phone.getUiccCard();
@@ -2413,7 +2462,7 @@
     @Override
     public boolean setLine1NumberForDisplayForSubscriber(int subId, String alphaTag,
             String number) {
-        enforceCarrierPrivilege();
+        enforceCarrierPrivilege(subId);
 
         final String iccId = getIccId(subId);
         final Phone phone = getPhone(subId);
@@ -2565,17 +2614,22 @@
     }
 
     @Override
-    public boolean setOperatorBrandOverride(String brand) {
-        enforceCarrierPrivilege();
-        return mPhone.setOperatorBrandOverride(brand);
+    public boolean setOperatorBrandOverride(int subId, String brand) {
+        enforceCarrierPrivilege(subId);
+        final Phone phone = getPhone(subId);
+        return phone == null ? false : phone.setOperatorBrandOverride(brand);
     }
 
     @Override
-    public boolean setRoamingOverride(List<String> gsmRoamingList,
+    public boolean setRoamingOverride(int subId, List<String> gsmRoamingList,
             List<String> gsmNonRoamingList, List<String> cdmaRoamingList,
             List<String> cdmaNonRoamingList) {
-        enforceCarrierPrivilege();
-        return mPhone.setRoamingOverride(gsmRoamingList, gsmNonRoamingList, cdmaRoamingList,
+        enforceCarrierPrivilege(subId);
+        final Phone phone = getPhone(subId);
+        if (phone == null) {
+            return false;
+        }
+        return phone.setRoamingOverride(gsmRoamingList, gsmNonRoamingList, cdmaRoamingList,
                 cdmaNonRoamingList);
     }
 
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 0142d64..3eff38f 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -30,6 +30,7 @@
 import android.telecom.StatusHints;
 import android.telecom.TelecomManager;
 import android.telephony.PhoneNumberUtils;
+import android.util.Pair;
 
 import com.android.ims.ImsCallProfile;
 import com.android.internal.telephony.Call;
@@ -77,6 +78,7 @@
     private static final int MSG_SET_CONFERENCE_PARTICIPANTS = 11;
     private static final int MSG_CONNECTION_EXTRAS_CHANGED = 12;
     private static final int MSG_SET_ORIGNAL_CONNECTION_CAPABILITIES = 13;
+    private static final int MSG_ON_HOLD_TONE = 14;
 
     private final Handler mHandler = new Handler() {
         @Override
@@ -180,6 +182,31 @@
                 case MSG_SET_ORIGNAL_CONNECTION_CAPABILITIES:
                     setOriginalConnectionCapabilities(msg.arg1);
                     break;
+
+                case MSG_ON_HOLD_TONE:
+                    AsyncResult asyncResult = (AsyncResult) msg.obj;
+                    Pair<com.android.internal.telephony.Connection, Boolean> heldInfo =
+                            (Pair<com.android.internal.telephony.Connection, Boolean>)
+                                    asyncResult.result;
+
+                    // Determines if the hold tone is starting or stopping.
+                    boolean playTone = ((Boolean) (heldInfo.second)).booleanValue();
+
+                    // Determine which connection the hold tone is stopping or starting for
+                    com.android.internal.telephony.Connection heldConnection = heldInfo.first;
+
+                    // Only start or stop the hold tone if this is the connection which is starting
+                    // or stopping the hold tone.
+                    if (heldConnection == mOriginalConnection) {
+                        // If starting the hold tone, send a connection event to Telecom which will
+                        // cause it to play the on hold tone.
+                        if (playTone) {
+                            sendConnectionEvent(EVENT_ON_HOLD_TONE_START);
+                        } else {
+                            sendConnectionEvent(EVENT_ON_HOLD_TONE_END);
+                        }
+                    }
+                    break;
             }
         }
     };
@@ -646,6 +673,7 @@
         getPhone().registerForRingbackTone(mHandler, MSG_RINGBACK_TONE, null);
         getPhone().registerForDisconnect(mHandler, MSG_DISCONNECT, null);
         getPhone().registerForSuppServiceNotification(mHandler, MSG_SUPP_SERVICE_NOTIFY, null);
+        getPhone().registerForOnHoldTone(mHandler, MSG_ON_HOLD_TONE, null);
         mOriginalConnection.addPostDialListener(mPostDialListener);
         mOriginalConnection.addListener(mOriginalConnectionListener);
 
@@ -718,6 +746,7 @@
                 getPhone().unregisterForHandoverStateChanged(mHandler);
                 getPhone().unregisterForDisconnect(mHandler);
                 getPhone().unregisterForSuppServiceNotification(mHandler);
+                getPhone().unregisterForOnHoldTone(mHandler);
             }
             mOriginalConnection.removePostDialListener(mPostDialListener);
             mOriginalConnection.removeListener(mOriginalConnectionListener);
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 010d549..d93fb96 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -539,17 +539,25 @@
     }
 
     private Phone getPhoneForAccount(PhoneAccountHandle accountHandle, boolean isEmergency) {
-        if (isEmergency) {
-            return PhoneFactory.getDefaultPhone();
-        }
-
+        Phone chosenPhone = null;
         int subId = PhoneUtils.getSubIdForPhoneAccountHandle(accountHandle);
         if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
             int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
-            return PhoneFactory.getPhone(phoneId);
+            chosenPhone = PhoneFactory.getPhone(phoneId);
         }
 
-        return null;
+        // If this is an emergency call and the phone we originally planned to make this call
+        // with is not in service or was invalid, try to find one that is in service, using the
+        // default as a last chance backup.
+        if (isEmergency && (chosenPhone == null || ServiceState.STATE_IN_SERVICE != chosenPhone
+                .getServiceState().getState())) {
+            Log.d(this, "getPhoneForAccount: phone for phone acct handle %s is out of service "
+                    + "or invalid for emergency call.", accountHandle);
+            chosenPhone = getFirstPhoneForEmergencyCall();
+            Log.d(this, "getPhoneForAccount: using subId: " +
+                    (chosenPhone == null ? "null" : chosenPhone.getSubId()));
+        }
+        return chosenPhone;
     }
 
     private Phone getFirstPhoneForEmergencyCall() {
@@ -566,23 +574,23 @@
 
             if (ServiceState.STATE_IN_SERVICE == phone.getServiceState().getState()) {
                 // the slot is radio on & state is in service
-                Log.d(this, "pickBestPhoneForEmergencyCall, radio on & in service, slotId:" + i);
+                Log.d(this, "getFirstPhoneForEmergencyCall, radio on & in service, slotId:" + i);
                 return phone;
             } else if (ServiceState.STATE_POWER_OFF != phone.getServiceState().getState()) {
                 // the slot is radio on & with SIM card inserted.
                 if (TelephonyManager.getDefault().hasIccCard(i)) {
-                    Log.d(this, "pickBestPhoneForEmergencyCall," +
+                    Log.d(this, "getFirstPhoneForEmergencyCall," +
                             "radio on and SIM card inserted, slotId:" + i);
                     selectPhone = phone;
                 } else if (selectPhone == null) {
-                    Log.d(this, "pickBestPhoneForEmergencyCall, radio on, slotId:" + i);
+                    Log.d(this, "getFirstPhoneForEmergencyCall, radio on, slotId:" + i);
                     selectPhone = phone;
                 }
             }
         }
 
         if (selectPhone == null) {
-            Log.d(this, "pickBestPhoneForEmergencyCall, return default phone");
+            Log.d(this, "getFirstPhoneForEmergencyCall, return default phone");
             selectPhone = PhoneFactory.getDefaultPhone();
         }