Merge "packages/services/Telecomm: Set LOCAL_SDK_VERSION where possible."
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index e485e88..4c29e45 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -60,7 +60,6 @@
 import java.lang.String;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.LinkedList;
@@ -487,11 +486,6 @@
     private ParcelFileDescriptor[] mConnectionServiceToInCallStreams;
 
     /**
-     * Abandoned RTT pipes, to be cleaned up when the call is removed
-     */
-    private Collection<ParcelFileDescriptor> mDiscardedRttFds = new LinkedList<>();
-
-    /**
      * True if we're supposed to start this call with RTT, either due to the master switch or due
      * to an extra.
      */
@@ -671,16 +665,33 @@
             mCallerInfo.cachedPhotoIcon = null;
             mCallerInfo.cachedPhoto = null;
         }
-        for (ParcelFileDescriptor fd : mDiscardedRttFds) {
-            if (fd != null) {
-                try {
-                    fd.close();
-                } catch (IOException e) {
-                    // ignore
+
+        Log.addEvent(this, LogUtils.Events.DESTROYED);
+    }
+
+    private void closeRttStreams() {
+        if (mConnectionServiceToInCallStreams != null) {
+            for (ParcelFileDescriptor fd : mConnectionServiceToInCallStreams) {
+                if (fd != null) {
+                    try {
+                        fd.close();
+                    } catch (IOException e) {
+                        // ignore
+                    }
                 }
             }
         }
-        Log.addEvent(this, LogUtils.Events.DESTROYED);
+        if (mInCallToConnectionServiceStreams != null) {
+            for (ParcelFileDescriptor fd : mInCallToConnectionServiceStreams) {
+                if (fd != null) {
+                    try {
+                        fd.close();
+                    } catch (IOException e) {
+                        // ignore
+                    }
+                }
+            }
+        }
     }
 
     /** {@inheritDoc} */
@@ -1308,12 +1319,8 @@
                 && mDidRequestToStartWithRtt && !areRttStreamsInitialized()) {
             // If the phone account got set to an RTT capable one and we haven't set the streams
             // yet, do so now.
-            setRttStreams(true);
+            createRttStreams();
             Log.i(this, "Setting RTT streams after target phone account selected");
-        } else if (!isRttSupported && !isConnectionManagerRttSupported) {
-            // If the phone account got set to RTT-incapable, unset the streams.
-            Log.i(this, "Unsetting RTT streams after target phone account selected");
-            setRttStreams(false);
         }
     }
 
@@ -1418,8 +1425,10 @@
         if (changedProperties != 0) {
             int previousProperties = mConnectionProperties;
             mConnectionProperties = connectionProperties;
-            setRttStreams((mConnectionProperties & Connection.PROPERTY_IS_RTT) ==
-                    Connection.PROPERTY_IS_RTT);
+            if ((mConnectionProperties & Connection.PROPERTY_IS_RTT) ==
+                    Connection.PROPERTY_IS_RTT) {
+                createRttStreams();
+            }
             mWasHighDefAudio = (connectionProperties & Connection.PROPERTY_HIGH_DEF_AUDIO) ==
                     Connection.PROPERTY_HIGH_DEF_AUDIO;
             boolean didRttChange =
@@ -2525,7 +2534,7 @@
     }
 
     public void sendRttRequest() {
-        setRttStreams(true);
+        createRttStreams();
         mConnectionService.startRtt(this, getInCallToCsRttPipeForCs(), getCsToInCallRttPipeForCs());
     }
 
@@ -2534,10 +2543,9 @@
                 && mConnectionServiceToInCallStreams != null;
     }
 
-    public void setRttStreams(boolean shouldBeRtt) {
-        boolean areStreamsInitialized = areRttStreamsInitialized();
-        Log.i(this, "Setting RTT streams to %b, currently %b", shouldBeRtt, areStreamsInitialized);
-        if (shouldBeRtt && !areStreamsInitialized) {
+    public void createRttStreams() {
+        if (!areRttStreamsInitialized()) {
+            Log.i(this, "Initializing RTT streams");
             try {
                 mWasEverRtt = true;
                 mInCallToConnectionServiceStreams = ParcelFileDescriptor.createReliablePipe();
@@ -2545,16 +2553,11 @@
             } catch (IOException e) {
                 Log.e(this, e, "Failed to create pipes for RTT call.");
             }
-        } else if (!shouldBeRtt && areStreamsInitialized) {
-            closeRttPipes();
-            mInCallToConnectionServiceStreams = null;
-            mConnectionServiceToInCallStreams = null;
         }
     }
 
     public void onRttConnectionFailure(int reason) {
         Log.i(this, "Got RTT initiation failure with reason %d", reason);
-        setRttStreams(false);
         for (Listener l : mListeners) {
             l.onRttInitiationFailure(this, reason);
         }
@@ -2581,8 +2584,8 @@
             Log.w(this, "Response ID %d does not match expected %d", id, mPendingRttRequestId);
             return;
         }
-        setRttStreams(accept);
         if (accept) {
+            createRttStreams();
             Log.i(this, "RTT request %d accepted.", id);
             mConnectionService.respondToRttRequest(
                     this, getInCallToCsRttPipeForCs(), getCsToInCallRttPipeForCs());
@@ -2592,18 +2595,6 @@
         }
     }
 
-    public void closeRttPipes() {
-        // Defer closing until the call is destroyed
-        if (mInCallToConnectionServiceStreams != null) {
-            mDiscardedRttFds.add(mInCallToConnectionServiceStreams[0]);
-            mDiscardedRttFds.add(mInCallToConnectionServiceStreams[1]);
-        }
-        if (mConnectionServiceToInCallStreams != null) {
-            mDiscardedRttFds.add(mConnectionServiceToInCallStreams[0]);
-            mDiscardedRttFds.add(mConnectionServiceToInCallStreams[1]);
-        }
-    }
-
     public boolean isRttCall() {
         return (mConnectionProperties & Connection.PROPERTY_IS_RTT) == Connection.PROPERTY_IS_RTT;
     }
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index ab06209..4b328f5 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -364,7 +364,13 @@
         return null;
     }
 
-    void toggleMute() {
+    @VisibleForTesting
+    public void toggleMute() {
+        // Don't mute if there are any emergency calls.
+        if (mCallsManager.hasEmergencyCall()) {
+            Log.v(this, "ignoring toggleMute for emergency call");
+            return;
+        }
         mCallAudioRouteStateMachine.sendMessageWithSessionInfo(
                 CallAudioRouteStateMachine.TOGGLE_MUTE);
     }
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index e83f28b..4c5a74e 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -915,12 +915,12 @@
                 call.setIsVoipAudioMode(true);
             }
         }
-        if (isRttSettingOn() ||
+        if (isRttSettingOn() &&
                 extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) {
             Log.d(this, "Incoming call requesting RTT, rtt setting is %b", isRttSettingOn());
             if (phoneAccount != null &&
                     phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) {
-                call.setRttStreams(true);
+                call.createRttStreams();
             }
             // Even if the phone account doesn't support RTT yet, the connection manager might
             // change that. Set this to check it later.
@@ -1211,7 +1211,7 @@
                 Log.d(this, "Outgoing call requesting RTT, rtt setting is %b", isRttSettingOn());
                 if (accountToUse != null
                         && accountToUse.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) {
-                    call.setRttStreams(true);
+                    call.createRttStreams();
                 }
                 // Even if the phone account doesn't support RTT yet, the connection manager might
                 // change that. Set this to check it later.
@@ -1778,8 +1778,7 @@
 
     private boolean isRttSettingOn() {
         return Settings.System.getInt(mContext.getContentResolver(),
-                Settings.System.RTT_CALLING_MODE, TelecomManager.TTY_MODE_OFF)
-                != TelecomManager.TTY_MODE_OFF;
+                Settings.System.RTT_CALLING_MODE, 0) != 0;
     }
 
     void phoneAccountSelected(Call call, PhoneAccountHandle account, boolean setDefault) {
@@ -1801,7 +1800,7 @@
                         " rtt setting is %b", isRttSettingOn());
                 if (realPhoneAccount != null
                         && realPhoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) {
-                    call.setRttStreams(true);
+                    call.createRttStreams();
                 }
                 // Even if the phone account doesn't support RTT yet, the connection manager might
                 // change that. Set this to check it later.
@@ -1859,6 +1858,7 @@
     void markCallAsDialing(Call call) {
         setCallState(call, CallState.DIALING, "dialing set explicitly");
         maybeMoveToSpeakerPhone(call);
+        maybeTurnOffMute(call);
     }
 
     void markCallAsPulling(Call call) {
@@ -2854,6 +2854,15 @@
     }
 
     /**
+     * Checks to see if the call is an emergency call and if so, turn off mute.
+     */
+    private void maybeTurnOffMute(Call call) {
+        if (call.isEmergencyCall()) {
+            mute(false);
+        }
+    }
+
+    /**
      * Creates a new call for an existing connection.
      *
      * @param callId The id of the new call.
diff --git a/src/com/android/server/telecom/ParcelableCallUtils.java b/src/com/android/server/telecom/ParcelableCallUtils.java
index 3c0e756..77598c8 100644
--- a/src/com/android/server/telecom/ParcelableCallUtils.java
+++ b/src/com/android/server/telecom/ParcelableCallUtils.java
@@ -342,7 +342,10 @@
         android.telecom.Call.Details.PROPERTY_SELF_MANAGED,
 
         Connection.PROPERTY_ASSISTED_DIALING_USED,
-        android.telecom.Call.Details.PROPERTY_ASSISTED_DIALING_USED
+        android.telecom.Call.Details.PROPERTY_ASSISTED_DIALING_USED,
+
+        Connection.PROPERTY_IS_RTT,
+        android.telecom.Call.Details.PROPERTY_RTT
     };
 
     private static int convertConnectionToCallProperties(int connectionProperties) {
diff --git a/tests/src/com/android/server/telecom/tests/BasicCallTests.java b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
index 64abd14..9302eaa 100644
--- a/tests/src/com/android/server/telecom/tests/BasicCallTests.java
+++ b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
@@ -27,6 +27,7 @@
 import static org.mockito.Matchers.isNull;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
@@ -68,6 +69,7 @@
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
+import java.util.List;
 import java.util.concurrent.BrokenBarrierException;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.CyclicBarrier;
@@ -1068,4 +1070,48 @@
                 .deflect(eq(ids.mConnectionId), eq(deflectAddress), any());
         mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
     }
+
+    /**
+     * Test to make sure to unmute automatically when making an emergency call and keep unmute
+     * during the emergency call.
+     * @throws Exception
+     */
+    @LargeTest
+    @Test
+    public void testUnmuteDuringEmergencyCall() throws Exception {
+        // Make an outgoing call and turn ON mute.
+        IdPair outgoingCall = startAndMakeActiveOutgoingCall("650-555-1212",
+                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(outgoingCall.mCallId)
+                .getState());
+        mInCallServiceFixtureX.mInCallAdapter.mute(true);
+        waitForHandlerAction(mTelecomSystem.getCallsManager().getCallAudioManager()
+                .getCallAudioRouteStateMachine().getHandler(), TEST_TIMEOUT);
+        assertTrue(mTelecomSystem.getCallsManager().getAudioState().isMuted());
+
+        // Make an emergency call.
+        IdPair emergencyCall = startAndMakeDialingEmergencyCall("650-555-1213",
+                mPhoneAccountE0.getAccountHandle(), mConnectionServiceFixtureA);
+        assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(emergencyCall.mCallId)
+                .getState());
+        waitForHandlerAction(mTelecomSystem.getCallsManager().getCallAudioManager()
+                .getCallAudioRouteStateMachine().getHandler(), TEST_TIMEOUT);
+        // Should be unmute automatically.
+        assertFalse(mTelecomSystem.getCallsManager().getAudioState().isMuted());
+
+        // Toggle mute during an emergency call.
+        mTelecomSystem.getCallsManager().getCallAudioManager().toggleMute();
+        waitForHandlerAction(mTelecomSystem.getCallsManager().getCallAudioManager()
+                .getCallAudioRouteStateMachine().getHandler(), TEST_TIMEOUT);
+        // Should keep unmute.
+        assertFalse(mTelecomSystem.getCallsManager().getAudioState().isMuted());
+
+        ArgumentCaptor<Boolean> muteValueCaptor = ArgumentCaptor.forClass(Boolean.class);
+        verify(mAudioService, times(2)).setMicrophoneMute(muteValueCaptor.capture(),
+                any(String.class), any(Integer.class));
+        List<Boolean> muteValues = muteValueCaptor.getAllValues();
+        // Check mute status was changed twice with true and false.
+        assertTrue(muteValues.get(0));
+        assertFalse(muteValues.get(1));
+    }
 }