Remove hold and merge from emergency calls

Removes the ability for emergency calls to be placed on hold or merged
with other calls into a conference.

Bug: 25219137
Change-Id: Iaf77394491542ccd3200287a917154174cb150c5
diff --git a/src/com/android/services/telephony/GsmConnection.java b/src/com/android/services/telephony/GsmConnection.java
index 4bd7a32..dd47e8d 100644
--- a/src/com/android/services/telephony/GsmConnection.java
+++ b/src/com/android/services/telephony/GsmConnection.java
@@ -60,9 +60,11 @@
     protected int buildConnectionCapabilities() {
         int capabilities = super.buildConnectionCapabilities();
         capabilities |= CAPABILITY_MUTE;
-        capabilities |= CAPABILITY_SUPPORT_HOLD;
-        if (getState() == STATE_ACTIVE || getState() == STATE_HOLDING) {
-            capabilities |= CAPABILITY_HOLD;
+        if (!shouldTreatAsEmergencyCall()) {
+            capabilities |= CAPABILITY_SUPPORT_HOLD;
+            if (getState() == STATE_ACTIVE || getState() == STATE_HOLDING) {
+                capabilities |= CAPABILITY_HOLD;
+            }
         }
         return capabilities;
     }
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index ca2d58a..50d2ad0 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -28,6 +28,7 @@
 import android.telecom.Connection;
 import android.telecom.PhoneAccount;
 import android.telecom.StatusHints;
+import android.telephony.PhoneNumberUtils;
 
 import com.android.ims.ImsCallProfile;
 import com.android.internal.telephony.Call;
@@ -326,7 +327,7 @@
         }
     };
 
-    private com.android.internal.telephony.Connection mOriginalConnection;
+    protected com.android.internal.telephony.Connection mOriginalConnection;
     private Call.State mConnectionState = Call.State.IDLE;
     private Bundle mOriginalConnectionExtras = new Bundle();
     private boolean mIsStateOverridden = false;
@@ -374,6 +375,13 @@
     private boolean mHasHighDefAudio;
 
     /**
+     * Indicates that the connection should be treated as an emergency call because the
+     * number dialed matches an internal list of emergency numbers. Does not guarantee whether
+     * the network will treat the call as an emergency call.
+     */
+    private boolean mTreatAsEmergencyCall;
+
+    /**
      * For video calls, indicates whether the outgoing video for the call can be paused using
      * the {@link android.telecom.VideoProfile#STATE_PAUSED} VideoState.
      */
@@ -594,9 +602,11 @@
             if (mOriginalConnection.isIncoming()) {
                 callCapabilities |= CAPABILITY_SPEED_UP_MT_AUDIO;
             }
-            callCapabilities |= CAPABILITY_SUPPORT_HOLD;
-            if (getState() == STATE_ACTIVE || getState() == STATE_HOLDING) {
-                callCapabilities |= CAPABILITY_HOLD;
+            if (!shouldTreatAsEmergencyCall()) {
+                callCapabilities |= CAPABILITY_SUPPORT_HOLD;
+                if (getState() == STATE_ACTIVE || getState() == STATE_HOLDING) {
+                    callCapabilities |= CAPABILITY_HOLD;
+                }
             }
         }
 
@@ -647,6 +657,10 @@
                 Log.v(this, "updateAddress, caller display name changed");
                 setCallerDisplayName(name, namePresentation);
             }
+
+            if (PhoneNumberUtils.isEmergencyNumber(mOriginalConnection.getAddress())) {
+                mTreatAsEmergencyCall = true;
+            }
         }
     }
 
@@ -679,6 +693,10 @@
         setAudioQuality(mOriginalConnection.getAudioQuality());
         updateExtras(mOriginalConnection.getConnectionExtras());
 
+        if (PhoneNumberUtils.isEmergencyNumber(mOriginalConnection.getAddress())) {
+            mTreatAsEmergencyCall = true;
+        }
+
         if (isImsConnection()) {
             mWasImsConnection = true;
         }
@@ -696,6 +714,15 @@
     }
 
     /**
+     * Whether the connection should be treated as an emergency.
+     * @return {@code true} if the connection should be treated as an emergency call based
+     * on the number dialed, {@code false} otherwise.
+     */
+    protected boolean shouldTreatAsEmergencyCall() {
+        return mTreatAsEmergencyCall;
+    }
+
+    /**
      * Un-sets the underlying radio connection.
      */
     void clearOriginalConnection() {
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index d28239e..e2d3832 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -279,7 +279,7 @@
 
         final TelephonyConnection connection =
                 createConnectionFor(phone, null, true /* isOutgoing */, request.getAccountHandle(),
-                        request.getTelecomCallId());
+                        request.getTelecomCallId(), request.getAddress());
         if (connection == null) {
             return Connection.createFailedConnection(
                     DisconnectCauseUtil.toTelecomDisconnectCause(
@@ -354,7 +354,8 @@
 
         Connection connection =
                 createConnectionFor(phone, originalConnection, false /* isOutgoing */,
-                        request.getAccountHandle(), request.getTelecomCallId());
+                        request.getAccountHandle(), request.getTelecomCallId(),
+                        request.getAddress());
         if (connection == null) {
             return Connection.createCanceledConnection();
         } else {
@@ -420,7 +421,8 @@
         TelephonyConnection connection =
                 createConnectionFor(phone, unknownConnection,
                         !unknownConnection.isIncoming() /* isOutgoing */,
-                        request.getAccountHandle(), request.getTelecomCallId());
+                        request.getAccountHandle(), request.getTelecomCallId(),
+                        request.getAddress());
 
         if (connection == null) {
             return Connection.createCanceledConnection();
@@ -483,7 +485,8 @@
             com.android.internal.telephony.Connection originalConnection,
             boolean isOutgoing,
             PhoneAccountHandle phoneAccountHandle,
-            String telecomCallId) {
+            String telecomCallId,
+            Uri address) {
         TelephonyConnection returnConnection = null;
         int phoneType = phone.getPhoneType();
         if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
@@ -499,8 +502,10 @@
             returnConnection.setVideoPauseSupported(
                     TelecomAccountRegistry.getInstance(this).isVideoPauseSupported(
                             phoneAccountHandle));
-            returnConnection.setConferenceSupported(
-                    TelecomAccountRegistry.getInstance(this).isMergeCallSupported(
+            boolean isEmergencyCall = (address != null && PhoneNumberUtils.isEmergencyNumber(
+                    address.getSchemeSpecificPart()));
+            returnConnection.setConferenceSupported(!isEmergencyCall
+                    && TelecomAccountRegistry.getInstance(this).isMergeCallSupported(
                             phoneAccountHandle));
         }
         return returnConnection;