RTT initialization bugfixes am: fb8d5abd22
am: bb39d8595f

Change-Id: I669cad9ef18f2c6bd0c03e195aae7a7350f61b77
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index f4c066b..e485e88 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -60,6 +60,7 @@
 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;
@@ -484,6 +485,17 @@
      */
     private ParcelFileDescriptor[] mInCallToConnectionServiceStreams;
     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.
+     */
+    private boolean mDidRequestToStartWithRtt = false;
     /**
      * Integer constant from {@link android.telecom.Call.RttCall}. Describes the current RTT mode.
      */
@@ -659,6 +671,15 @@
             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);
     }
 
@@ -1068,7 +1089,7 @@
                 l.onConnectionManagerPhoneAccountChanged(this);
             }
         }
-
+        checkIfRttCapable();
     }
 
     @VisibleForTesting
@@ -1086,6 +1107,7 @@
             configureCallAttributes();
         }
         checkIfVideoCapable();
+        checkIfRttCapable();
     }
 
     public CharSequence getTargetPhoneAccountLabel() {
@@ -1264,6 +1286,37 @@
         }
     }
 
+    private void checkIfRttCapable() {
+        PhoneAccountRegistrar phoneAccountRegistrar = mCallsManager.getPhoneAccountRegistrar();
+        if (mTargetPhoneAccountHandle == null) {
+            return;
+        }
+
+        // Check both the target phone account and the connection manager phone account -- if
+        // either support RTT, just set the streams and have them set/unset the RTT property as
+        // needed.
+        PhoneAccount phoneAccount =
+                phoneAccountRegistrar.getPhoneAccountUnchecked(mTargetPhoneAccountHandle);
+        PhoneAccount connectionManagerPhoneAccount = phoneAccountRegistrar.getPhoneAccountUnchecked(
+                        mConnectionManagerPhoneAccountHandle);
+        boolean isRttSupported = phoneAccount != null && phoneAccount.hasCapabilities(
+                PhoneAccount.CAPABILITY_RTT);
+        boolean isConnectionManagerRttSupported = connectionManagerPhoneAccount != null
+                && connectionManagerPhoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_RTT);
+
+        if ((isConnectionManagerRttSupported || isRttSupported)
+                && 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);
+            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);
+        }
+    }
+
     boolean shouldAttachToExistingConnection() {
         return mShouldAttachToExistingConnection;
     }
@@ -2457,6 +2510,10 @@
         return mSpeakerphoneOn;
     }
 
+    public void setRequestedToStartWithRtt() {
+        mDidRequestToStartWithRtt = true;
+    }
+
     public void stopRtt() {
         if (mConnectionService != null) {
             mConnectionService.stopRtt(this);
@@ -2472,9 +2529,14 @@
         mConnectionService.startRtt(this, getInCallToCsRttPipeForCs(), getCsToInCallRttPipeForCs());
     }
 
-    public void setRttStreams(boolean shouldBeRtt) {
-        boolean areStreamsInitialized = mInCallToConnectionServiceStreams != null
+    private boolean areRttStreamsInitialized() {
+        return mInCallToConnectionServiceStreams != null
                 && 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) {
             try {
                 mWasEverRtt = true;
@@ -2491,6 +2553,7 @@
     }
 
     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);
@@ -2530,7 +2593,15 @@
     }
 
     public void closeRttPipes() {
-        // TODO: may defer this until call is removed?
+        // 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() {
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 7ee4ac8..e83f28b 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -915,11 +915,16 @@
                 call.setIsVoipAudioMode(true);
             }
         }
-        if (extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) {
+        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);
             }
+            // Even if the phone account doesn't support RTT yet, the connection manager might
+            // change that. Set this to check it later.
+            call.setRequestedToStartWithRtt();
         }
         // If the extras specifies a video state, set it on the call if the PhoneAccount supports
         // video.
@@ -1201,12 +1206,16 @@
                     CallState.CONNECTING,
                     phoneAccountHandle == null ? "no-handle" : phoneAccountHandle.toString());
 
-            if (extras != null
-                    && extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) {
+            if (isRttSettingOn() || (extras != null
+                    && extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false))) {
+                Log.d(this, "Outgoing call requesting RTT, rtt setting is %b", isRttSettingOn());
                 if (accountToUse != null
                         && accountToUse.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) {
                     call.setRttStreams(true);
                 }
+                // Even if the phone account doesn't support RTT yet, the connection manager might
+                // change that. Set this to check it later.
+                call.setRequestedToStartWithRtt();
             }
         }
         setIntentExtrasAndStartTime(call, extras);
@@ -1767,6 +1776,12 @@
         mProximitySensorManager.turnOff(screenOnImmediately);
     }
 
+    private boolean isRttSettingOn() {
+        return Settings.System.getInt(mContext.getContentResolver(),
+                Settings.System.RTT_CALLING_MODE, TelecomManager.TTY_MODE_OFF)
+                != TelecomManager.TTY_MODE_OFF;
+    }
+
     void phoneAccountSelected(Call call, PhoneAccountHandle account, boolean setDefault) {
         if (!mCalls.contains(call)) {
             Log.i(this, "Attempted to add account to unknown call %s", call);
@@ -1780,12 +1795,17 @@
                 Log.d("phoneAccountSelected: default to voip mode for call %s", call.getId());
                 call.setIsVoipAudioMode(true);
             }
-            if (call.getIntentExtras()
+            if (isRttSettingOn() || call.getIntentExtras()
                     .getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) {
+                Log.d(this, "Outgoing call after account selection requesting RTT," +
+                        " rtt setting is %b", isRttSettingOn());
                 if (realPhoneAccount != null
                         && realPhoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) {
                     call.setRttStreams(true);
                 }
+                // Even if the phone account doesn't support RTT yet, the connection manager might
+                // change that. Set this to check it later.
+                call.setRequestedToStartWithRtt();
             }
 
             if (!call.isNewOutgoingCallIntentBroadcastDone()) {