Add simulator RTT call.

This change will also:
1. Disable proximity sensor for RTT call
2. Update RTT call screen, including colors and banner buttons

Bug: 67596257
Test: presubmit
PiperOrigin-RevId: 185541897
Change-Id: I571373efbb8ced4ee2ad94879e9d37bed33b6a28
diff --git a/java/com/android/dialer/common/res/values/strings.xml b/java/com/android/dialer/common/res/values/strings.xml
index 770f42f..53a2b56 100644
--- a/java/com/android/dialer/common/res/values/strings.xml
+++ b/java/com/android/dialer/common/res/values/strings.xml
@@ -17,4 +17,6 @@
 <resources>
   <string name="network_name_wifi">Wifi</string>
   <string name="network_name_mobile">Mobile</string>
+  <!-- Content description for the overflow menu button. [CHAR LIMIT=NONE] -->
+  <string name="content_description_overflow">More options</string>
 </resources>
diff --git a/java/com/android/dialer/simulator/Simulator.java b/java/com/android/dialer/simulator/Simulator.java
index 3c2526b..11a07d9 100644
--- a/java/com/android/dialer/simulator/Simulator.java
+++ b/java/com/android/dialer/simulator/Simulator.java
@@ -101,6 +101,9 @@
       MERGE,
       SEPARATE,
       SWAP,
+      START_RTT,
+      STOP_RTT,
+      HANDLE_RTT_UPGRADE_RESPONSE,
     })
     public @interface Type {}
 
@@ -118,6 +121,9 @@
     public static final int MERGE = 11;
     public static final int SEPARATE = 12;
     public static final int SWAP = 13;
+    public static final int START_RTT = 14;
+    public static final int STOP_RTT = 15;
+    public static final int HANDLE_RTT_UPGRADE_RESPONSE = 16;
 
     @Type public final int type;
     /** Holds event specific information. For example, for DTMF this could be the keycode. */
diff --git a/java/com/android/dialer/simulator/impl/SimulatorConferenceCreator.java b/java/com/android/dialer/simulator/impl/SimulatorConferenceCreator.java
index 2bfa982..81a3d30 100644
--- a/java/com/android/dialer/simulator/impl/SimulatorConferenceCreator.java
+++ b/java/com/android/dialer/simulator/impl/SimulatorConferenceCreator.java
@@ -97,7 +97,8 @@
       default:
         break;
     }
-    SimulatorSimCallManager.addNewIncomingCall(context, number, false /* isVideo */, extras);
+    SimulatorSimCallManager.addNewIncomingCall(
+        context, number, SimulatorSimCallManager.CALL_TYPE_VOICE, extras);
   }
 
   @Override
diff --git a/java/com/android/dialer/simulator/impl/SimulatorConnection.java b/java/com/android/dialer/simulator/impl/SimulatorConnection.java
index d7427dd..c832a50 100644
--- a/java/com/android/dialer/simulator/impl/SimulatorConnection.java
+++ b/java/com/android/dialer/simulator/impl/SimulatorConnection.java
@@ -121,6 +121,24 @@
     onEvent(new Event(Event.DTMF, Character.toString(c), null));
   }
 
+  @Override
+  public void onStartRtt(@NonNull RttTextStream rttTextStream) {
+    LogUtil.enterBlock("SimulatorConnection.onStartRtt");
+    onEvent(new Event(Event.START_RTT));
+  }
+
+  @Override
+  public void onStopRtt() {
+    LogUtil.enterBlock("SimulatorConnection.onStopRtt");
+    onEvent(new Event(Event.STOP_RTT));
+  }
+
+  @Override
+  public void handleRttUpgradeResponse(RttTextStream rttTextStream) {
+    LogUtil.enterBlock("SimulatorConnection.handleRttUpgradeResponse");
+    onEvent(new Event(Event.HANDLE_RTT_UPGRADE_RESPONSE));
+  }
+
   void onEvent(@NonNull Event event) {
     events.add(Assert.isNotNull(event));
     for (Listener listener : new ArrayList<>(listeners)) {
diff --git a/java/com/android/dialer/simulator/impl/SimulatorMainMenu.java b/java/com/android/dialer/simulator/impl/SimulatorMainMenu.java
index 0bd1c0f..1bf4b2a 100644
--- a/java/com/android/dialer/simulator/impl/SimulatorMainMenu.java
+++ b/java/com/android/dialer/simulator/impl/SimulatorMainMenu.java
@@ -33,7 +33,6 @@
 import com.android.dialer.persistentlog.PersistentLogger;
 import com.android.dialer.preferredsim.PreferredSimFallbackContract;
 import com.android.dialer.simulator.SimulatorComponent;
-import com.android.incallui.rtt.impl.RttChatActivity;
 
 /** Implements the top level simulator menu. */
 final class SimulatorMainMenu {
@@ -42,9 +41,9 @@
     SimulatorSubMenu simulatorSubMenu = new SimulatorSubMenu(activity.getApplicationContext());
     simulatorSubMenu
         .addItem("Voice call", SimulatorVoiceCall.getActionProvider(activity))
+        .addItem("Rtt call", SimulatorRttCall.getActionProvider(activity.getApplicationContext()))
         .addItem(
             "IMS video", SimulatorVideoCall.getActionProvider(activity.getApplicationContext()))
-        .addItem("Rtt call mock", () -> simulateRttCallMock(activity.getApplicationContext()))
         .addItem(
             "Notifications",
             SimulatorNotifications.getActionProvider(activity.getApplicationContext()))
@@ -79,10 +78,6 @@
     return simulatorSubMenu;
   }
 
-  private static void simulateRttCallMock(@NonNull Context context) {
-    context.startActivity(new Intent(context, RttChatActivity.class));
-  }
-
   private static void populateDatabase(@NonNull Context context) {
     DialerExecutorComponent.get(context)
         .dialerExecutorFactory()
diff --git a/java/com/android/dialer/simulator/impl/SimulatorMissedCallCreator.java b/java/com/android/dialer/simulator/impl/SimulatorMissedCallCreator.java
index 6d4a262..b855615 100644
--- a/java/com/android/dialer/simulator/impl/SimulatorMissedCallCreator.java
+++ b/java/com/android/dialer/simulator/impl/SimulatorMissedCallCreator.java
@@ -78,7 +78,8 @@
     extras.putInt(EXTRA_CALL_COUNT, callCount - 1);
     extras.putBoolean(EXTRA_IS_MISSED_CALL_CONNECTION, true);
 
-    SimulatorSimCallManager.addNewIncomingCall(context, callerId, false /* isVideo */, extras);
+    SimulatorSimCallManager.addNewIncomingCall(
+        context, callerId, SimulatorSimCallManager.CALL_TYPE_VOICE, extras);
   }
 
   private static boolean isMissedCallConnection(@NonNull Connection connection) {
diff --git a/java/com/android/dialer/simulator/impl/SimulatorRttCall.java b/java/com/android/dialer/simulator/impl/SimulatorRttCall.java
new file mode 100644
index 0000000..7b00667
--- /dev/null
+++ b/java/com/android/dialer/simulator/impl/SimulatorRttCall.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.simulator.impl;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.telecom.Connection;
+import android.telecom.DisconnectCause;
+import android.view.ActionProvider;
+import com.android.dialer.common.Assert;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.common.concurrent.ThreadUtil;
+import com.android.dialer.simulator.Simulator;
+import com.android.dialer.simulator.Simulator.Event;
+
+/** Entry point in the simulator to create voice calls. */
+final class SimulatorRttCall
+    implements SimulatorConnectionService.Listener, SimulatorConnection.Listener {
+
+  @NonNull private final Context context;
+  @Nullable private String connectionTag;
+
+  static ActionProvider getActionProvider(@NonNull Context context) {
+    return new SimulatorSubMenu(context)
+        .addItem("Incoming call", () -> new SimulatorRttCall(context).addNewIncomingCall(false))
+        .addItem("Outgoing call", () -> new SimulatorRttCall(context).addNewOutgoingCall())
+        .addItem("Emergency call", () -> new SimulatorRttCall(context).addNewEmergencyCall());
+  }
+
+  private SimulatorRttCall(@NonNull Context context) {
+    this.context = Assert.isNotNull(context);
+    SimulatorConnectionService.addListener(this);
+    SimulatorConnectionService.addListener(
+        new SimulatorConferenceCreator(context, Simulator.CONFERENCE_TYPE_GSM));
+  }
+
+  private void addNewIncomingCall(boolean isSpam) {
+    String callerId =
+        isSpam
+            ? "+1-661-778-3020" /* Blacklisted custom spam number */
+            : "+44 (0) 20 7031 3000" /* Google London office */;
+    connectionTag =
+        SimulatorSimCallManager.addNewIncomingCall(
+            context, callerId, SimulatorSimCallManager.CALL_TYPE_RTT);
+  }
+
+  private void addNewOutgoingCall() {
+    String callerId = "+55-31-2128-6800"; // Brazil office.
+    connectionTag =
+        SimulatorSimCallManager.addNewOutgoingCall(
+            context, callerId, SimulatorSimCallManager.CALL_TYPE_RTT);
+  }
+
+  private void addNewEmergencyCall() {
+    String callerId = "911";
+    connectionTag =
+        SimulatorSimCallManager.addNewIncomingCall(
+            context, callerId, SimulatorSimCallManager.CALL_TYPE_RTT);
+  }
+
+  @Override
+  public void onNewOutgoingConnection(@NonNull SimulatorConnection connection) {
+    if (isMyConnection(connection)) {
+      LogUtil.i("SimulatorRttCall.onNewOutgoingConnection", "connection created");
+      handleNewConnection(connection);
+
+      // Telecom will force the connection to switch to Dialing when we return it. Wait until after
+      // we're returned it before changing call state.
+      ThreadUtil.postOnUiThread(connection::setActive);
+    }
+  }
+
+  @Override
+  public void onNewIncomingConnection(@NonNull SimulatorConnection connection) {
+    if (isMyConnection(connection)) {
+      LogUtil.i("SimulatorRttCall.onNewIncomingConnection", "connection created");
+      handleNewConnection(connection);
+    }
+  }
+
+  @Override
+  public void onConference(
+      @NonNull SimulatorConnection connection1, @NonNull SimulatorConnection connection2) {}
+
+  private void handleNewConnection(@NonNull SimulatorConnection connection) {
+    connection.addListener(this);
+    connection.setConnectionProperties(
+        connection.getConnectionProperties() | Connection.PROPERTY_IS_RTT);
+  }
+
+  private boolean isMyConnection(@NonNull Connection connection) {
+    return connection.getExtras().getBoolean(connectionTag);
+  }
+
+  @Override
+  public void onEvent(@NonNull SimulatorConnection connection, @NonNull Event event) {
+    switch (event.type) {
+      case Event.NONE:
+        throw Assert.createIllegalStateFailException();
+      case Event.ANSWER:
+        connection.setActive();
+        break;
+      case Event.REJECT:
+        connection.setDisconnected(new DisconnectCause(DisconnectCause.REJECTED));
+        break;
+      case Event.HOLD:
+        connection.setOnHold();
+        break;
+      case Event.UNHOLD:
+        connection.setActive();
+        break;
+      case Event.DISCONNECT:
+        connection.setDisconnected(new DisconnectCause(DisconnectCause.LOCAL));
+        break;
+      case Event.SESSION_MODIFY_REQUEST:
+        ThreadUtil.postDelayedOnUiThread(() -> connection.handleSessionModifyRequest(event), 2000);
+        break;
+      default:
+        LogUtil.i("SimulatorRttCall.onEvent", "unexpected event: " + event.type);
+        break;
+    }
+  }
+}
diff --git a/java/com/android/dialer/simulator/impl/SimulatorSimCallManager.java b/java/com/android/dialer/simulator/impl/SimulatorSimCallManager.java
index f28393c..d51e068 100644
--- a/java/com/android/dialer/simulator/impl/SimulatorSimCallManager.java
+++ b/java/com/android/dialer/simulator/impl/SimulatorSimCallManager.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.net.Uri;
 import android.os.Bundle;
+import android.support.annotation.IntDef;
 import android.support.annotation.NonNull;
 import android.telecom.Connection;
 import android.telecom.ConnectionRequest;
@@ -30,6 +31,8 @@
 import com.android.dialer.common.Assert;
 import com.android.dialer.common.LogUtil;
 import com.android.dialer.strictmode.StrictModeUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Random;
@@ -46,10 +49,20 @@
  */
 public class SimulatorSimCallManager {
 
+  public static final int CALL_TYPE_VOICE = 1;
+  public static final int CALL_TYPE_VIDEO = 2;
+  public static final int CALL_TYPE_RTT = 3;
+
+  /** Call type of a simulator call. */
+  @Retention(RetentionPolicy.SOURCE)
+  @IntDef({CALL_TYPE_VOICE, CALL_TYPE_VIDEO, CALL_TYPE_RTT})
+  public @interface CallType {}
+
   private static final String SIM_CALL_MANAGER_ACCOUNT_ID = "SIMULATOR_ACCOUNT_ID";
   private static final String VIDEO_PROVIDER_ACCOUNT_ID = "SIMULATOR_VIDEO_ACCOUNT_ID";
   private static final String EXTRA_IS_SIMULATOR_CONNECTION = "is_simulator_connection";
   private static final String EXTRA_CONNECTION_TAG = "connection_tag";
+  private static final String EXTRA_CONNECTION_CALL_TYPE = "connection_call_type";
 
   static void register(@NonNull Context context) {
     LogUtil.enterBlock("SimulatorSimCallManager.register");
@@ -75,15 +88,15 @@
 
   @NonNull
   public static String addNewOutgoingCall(
-      @NonNull Context context, @NonNull String phoneNumber, boolean isVideo) {
-    return addNewOutgoingCall(context, phoneNumber, isVideo, new Bundle());
+      @NonNull Context context, @NonNull String phoneNumber, @CallType int callType) {
+    return addNewOutgoingCall(context, phoneNumber, callType, new Bundle());
   }
 
   @NonNull
   public static String addNewOutgoingCall(
       @NonNull Context context,
       @NonNull String phoneNumber,
-      boolean isVideo,
+      @CallType int callType,
       @NonNull Bundle extras) {
     LogUtil.enterBlock("SimulatorSimCallManager.addNewOutgoingCall");
     Assert.isNotNull(context);
@@ -94,13 +107,18 @@
     register(context);
 
     extras = new Bundle(extras);
-    extras.putAll(createSimulatorConnectionExtras());
+    extras.putAll(createSimulatorConnectionExtras(callType));
 
     Bundle outgoingCallExtras = new Bundle();
     outgoingCallExtras.putBundle(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras);
     outgoingCallExtras.putParcelable(
         TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
-        isVideo ? getVideoProviderHandle(context) : getSystemPhoneAccountHandle(context));
+        callType == CALL_TYPE_VIDEO
+            ? getVideoProviderHandle(context)
+            : getSystemPhoneAccountHandle(context));
+    if (callType == CALL_TYPE_RTT) {
+      outgoingCallExtras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, true);
+    }
 
     TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
     try {
@@ -114,13 +132,16 @@
 
   @NonNull
   public static String addNewIncomingCall(
-      @NonNull Context context, @NonNull String callerId, boolean isVideo) {
-    return addNewIncomingCall(context, callerId, isVideo, new Bundle());
+      @NonNull Context context, @NonNull String callerId, @CallType int callType) {
+    return addNewIncomingCall(context, callerId, callType, new Bundle());
   }
 
   @NonNull
   public static String addNewIncomingCall(
-      @NonNull Context context, @NonNull String callerId, boolean isVideo, @NonNull Bundle extras) {
+      @NonNull Context context,
+      @NonNull String callerId,
+      @CallType int callType,
+      @NonNull Bundle extras) {
     LogUtil.enterBlock("SimulatorSimCallManager.addNewIncomingCall");
     Assert.isNotNull(context);
     Assert.isNotNull(callerId);
@@ -130,18 +151,21 @@
 
     extras = new Bundle(extras);
     extras.putString(TelephonyManager.EXTRA_INCOMING_NUMBER, callerId);
-    extras.putAll(createSimulatorConnectionExtras());
+    extras.putAll(createSimulatorConnectionExtras(callType));
 
     TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
     telecomManager.addNewIncomingCall(
-        isVideo ? getVideoProviderHandle(context) : getSystemPhoneAccountHandle(context), extras);
+        callType == CALL_TYPE_VIDEO
+            ? getVideoProviderHandle(context)
+            : getSystemPhoneAccountHandle(context),
+        extras);
     return extras.getString(EXTRA_CONNECTION_TAG);
   }
 
   @NonNull
   private static PhoneAccount buildSimCallManagerAccount(Context context) {
     return new PhoneAccount.Builder(getSimCallManagerHandle(context), "Simulator SIM call manager")
-        .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
+        .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER | PhoneAccount.CAPABILITY_RTT)
         .setShortDescription("Simulator SIM call manager")
         .setSupportedUriSchemes(Arrays.asList(PhoneAccount.SCHEME_TEL))
         .build();
@@ -218,12 +242,16 @@
   }
 
   @NonNull
-  static Bundle createSimulatorConnectionExtras() {
+  static Bundle createSimulatorConnectionExtras(@CallType int callType) {
     Bundle extras = new Bundle();
     extras.putBoolean(EXTRA_IS_SIMULATOR_CONNECTION, true);
     String connectionTag = createUniqueConnectionTag();
     extras.putString(EXTRA_CONNECTION_TAG, connectionTag);
     extras.putBoolean(connectionTag, true);
+    extras.putInt(EXTRA_CONNECTION_CALL_TYPE, callType);
+    if (callType == CALL_TYPE_RTT) {
+      extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, true);
+    }
     return extras;
   }
 
diff --git a/java/com/android/dialer/simulator/impl/SimulatorVideoCall.java b/java/com/android/dialer/simulator/impl/SimulatorVideoCall.java
index f7256a1..0bb56f1 100644
--- a/java/com/android/dialer/simulator/impl/SimulatorVideoCall.java
+++ b/java/com/android/dialer/simulator/impl/SimulatorVideoCall.java
@@ -77,7 +77,8 @@
     }
     String callerId = "+44 (0) 20 7031 3000"; // Google London office
     connectionTag =
-        SimulatorSimCallManager.addNewIncomingCall(context, callerId, true /* isVideo */);
+        SimulatorSimCallManager.addNewIncomingCall(
+            context, callerId, SimulatorSimCallManager.CALL_TYPE_VIDEO);
   }
 
   private void addNewOutgoingCall() {
@@ -87,7 +88,8 @@
     }
     String phoneNumber = "+44 (0) 20 7031 3000"; // Google London office
     connectionTag =
-        SimulatorSimCallManager.addNewOutgoingCall(context, phoneNumber, true /* isVideo */);
+        SimulatorSimCallManager.addNewOutgoingCall(
+            context, phoneNumber, SimulatorSimCallManager.CALL_TYPE_VIDEO);
   }
 
   @Override
diff --git a/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java b/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java
index 67a2db8..d4c7ee4 100644
--- a/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java
+++ b/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java
@@ -104,7 +104,10 @@
               extras.putBoolean(Simulator.IS_ENRICHED_CALL, true);
               connectionTag =
                   SimulatorSimCallManager.addNewIncomingCall(
-                      context, Simulator.ENRICHED_CALL_INCOMING_NUMBER, false, extras);
+                      context,
+                      Simulator.ENRICHED_CALL_INCOMING_NUMBER,
+                      SimulatorSimCallManager.CALL_TYPE_VOICE,
+                      extras);
             },
             DialerExecutorComponent.get(context).uiExecutor());
   }
@@ -119,7 +122,10 @@
               extras.putBoolean(Simulator.IS_ENRICHED_CALL, true);
               connectionTag =
                   SimulatorSimCallManager.addNewOutgoingCall(
-                      context, Simulator.ENRICHED_CALL_OUTGOING_NUMBER, false, extras);
+                      context,
+                      Simulator.ENRICHED_CALL_OUTGOING_NUMBER,
+                      SimulatorSimCallManager.CALL_TYPE_VOICE,
+                      extras);
             },
             DialerExecutorComponent.get(context).uiExecutor());
   }
@@ -127,7 +133,8 @@
   private void addNewIncomingCall() {
     String callerId = "+44 (0) 20 7031 3000" /* Google London office */;
     connectionTag =
-        SimulatorSimCallManager.addNewIncomingCall(context, callerId, false /* isVideo */);
+        SimulatorSimCallManager.addNewIncomingCall(
+            context, callerId, SimulatorSimCallManager.CALL_TYPE_VOICE);
   }
 
   private void addNewIncomingCall(AppCompatActivity activity) {
@@ -137,7 +144,7 @@
               extras.putInt(Simulator.PRESENTATION_CHOICE, callerIdPresentation);
               connectionTag =
                   SimulatorSimCallManager.addNewIncomingCall(
-                      context, callerId, false /* isVideo */, extras);
+                      context, callerId, SimulatorSimCallManager.CALL_TYPE_VOICE, extras);
             })
         .show(activity.getSupportFragmentManager(), "SimulatorDialog");
   }
@@ -145,7 +152,8 @@
   private void addNewOutgoingCall() {
     String callerId = "+55-31-2128-6800"; // Brazil office.
     connectionTag =
-        SimulatorSimCallManager.addNewOutgoingCall(context, callerId, false /* isVideo */);
+        SimulatorSimCallManager.addNewOutgoingCall(
+            context, callerId, SimulatorSimCallManager.CALL_TYPE_VOICE);
   }
 
   private void addNewOutgoingCall(AppCompatActivity activity) {
@@ -155,7 +163,7 @@
               extras.putInt(Simulator.PRESENTATION_CHOICE, callerIdPresentation);
               connectionTag =
                   SimulatorSimCallManager.addNewOutgoingCall(
-                      context, callerId, false /* isVideo */, extras);
+                      context, callerId, SimulatorSimCallManager.CALL_TYPE_VOICE, extras);
             })
         .show(activity.getSupportFragmentManager(), "SimulatorDialog");
   }
@@ -163,12 +171,15 @@
   private void addSpamIncomingCall() {
     String callerId = "+1-661-778-3020"; /* Blacklisted custom spam number */
     connectionTag =
-        SimulatorSimCallManager.addNewIncomingCall(context, callerId, false /* isVideo */);
+        SimulatorSimCallManager.addNewIncomingCall(
+            context, callerId, SimulatorSimCallManager.CALL_TYPE_VOICE);
   }
 
   private void addNewEmergencyCallBack() {
     String callerId = "911";
-    connectionTag = SimulatorSimCallManager.addNewIncomingCall(context, callerId, false);
+    connectionTag =
+        SimulatorSimCallManager.addNewIncomingCall(
+            context, callerId, SimulatorSimCallManager.CALL_TYPE_VOICE);
   }
 
   @Override
diff --git a/java/com/android/incallui/InCallActivity.java b/java/com/android/incallui/InCallActivity.java
index 8769be5..67f5cfe 100644
--- a/java/com/android/incallui/InCallActivity.java
+++ b/java/com/android/incallui/InCallActivity.java
@@ -83,6 +83,10 @@
 import com.android.incallui.incall.protocol.InCallScreenDelegate;
 import com.android.incallui.incall.protocol.InCallScreenDelegateFactory;
 import com.android.incallui.incalluilock.InCallUiLock;
+import com.android.incallui.rtt.bindings.RttBindings;
+import com.android.incallui.rtt.protocol.RttCallScreen;
+import com.android.incallui.rtt.protocol.RttCallScreenDelegate;
+import com.android.incallui.rtt.protocol.RttCallScreenDelegateFactory;
 import com.android.incallui.telecomeventui.InternationalCallOnWifiDialogFragment;
 import com.android.incallui.video.bindings.VideoBindings;
 import com.android.incallui.video.protocol.VideoCallScreen;
@@ -100,6 +104,7 @@
         InCallScreenDelegateFactory,
         InCallButtonUiDelegateFactory,
         VideoCallScreenDelegateFactory,
+        RttCallScreenDelegateFactory,
         PseudoScreenState.StateChangedListener {
 
   @Retention(RetentionPolicy.SOURCE)
@@ -136,6 +141,7 @@
   private boolean didShowAnswerScreen;
   private boolean didShowInCallScreen;
   private boolean didShowVideoCallScreen;
+  private boolean didShowRttCallScreen;
   private boolean dismissKeyguard;
   private boolean isInShowMainInCallFragment;
   private boolean isRecreating; // whether the activity is going to be recreated
@@ -1220,37 +1226,47 @@
     isInShowMainInCallFragment = true;
     ShouldShowUiResult shouldShowAnswerUi = getShouldShowAnswerUi();
     ShouldShowUiResult shouldShowVideoUi = getShouldShowVideoUi();
+    ShouldShowUiResult shouldShowRttUi = getShouldShowRttUi();
     LogUtil.i(
         "InCallActivity.showMainInCallFragment",
-        "shouldShowAnswerUi: %b, shouldShowVideoUi: %b, "
-            + "didShowAnswerScreen: %b, didShowInCallScreen: %b, didShowVideoCallScreen: %b",
+        "shouldShowAnswerUi: %b, shouldShowRttUi: %b, shouldShowVideoUi: %b "
+            + "didShowAnswerScreen: %b, didShowInCallScreen: %b, didShowRttCallScreen: %b, "
+            + "didShowVideoCallScreen: %b",
         shouldShowAnswerUi.shouldShow,
+        shouldShowRttUi.shouldShow,
         shouldShowVideoUi.shouldShow,
         didShowAnswerScreen,
         didShowInCallScreen,
+        didShowRttCallScreen,
         didShowVideoCallScreen);
     // Only video call ui allows orientation change.
     setAllowOrientationChange(shouldShowVideoUi.shouldShow);
 
     FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
-    boolean didChangeInCall;
-    boolean didChangeVideo;
-    boolean didChangeAnswer;
+    boolean didChange;
     if (shouldShowAnswerUi.shouldShow) {
-      didChangeInCall = hideInCallScreenFragment(transaction);
-      didChangeVideo = hideVideoCallScreenFragment(transaction);
-      didChangeAnswer = showAnswerScreenFragment(transaction, shouldShowAnswerUi.call);
+      didChange = hideInCallScreenFragment(transaction);
+      didChange |= hideVideoCallScreenFragment(transaction);
+      didChange |= hideRttCallScreenFragment(transaction);
+      didChange |= showAnswerScreenFragment(transaction, shouldShowAnswerUi.call);
     } else if (shouldShowVideoUi.shouldShow) {
-      didChangeInCall = hideInCallScreenFragment(transaction);
-      didChangeVideo = showVideoCallScreenFragment(transaction, shouldShowVideoUi.call);
-      didChangeAnswer = hideAnswerScreenFragment(transaction);
+      didChange = hideInCallScreenFragment(transaction);
+      didChange |= showVideoCallScreenFragment(transaction, shouldShowVideoUi.call);
+      didChange |= hideRttCallScreenFragment(transaction);
+      didChange |= hideAnswerScreenFragment(transaction);
+    } else if (shouldShowRttUi.shouldShow) {
+      didChange = hideInCallScreenFragment(transaction);
+      didChange |= hideVideoCallScreenFragment(transaction);
+      didChange |= hideAnswerScreenFragment(transaction);
+      didChange |= showRttCallScreenFragment(transaction, shouldShowRttUi.call);
     } else {
-      didChangeInCall = showInCallScreenFragment(transaction);
-      didChangeVideo = hideVideoCallScreenFragment(transaction);
-      didChangeAnswer = hideAnswerScreenFragment(transaction);
+      didChange = showInCallScreenFragment(transaction);
+      didChange |= hideVideoCallScreenFragment(transaction);
+      didChange |= hideRttCallScreenFragment(transaction);
+      didChange |= hideAnswerScreenFragment(transaction);
     }
 
-    if (didChangeInCall || didChangeVideo || didChangeAnswer) {
+    if (didChange) {
       Trace.beginSection("InCallActivity.commitTransaction");
       transaction.commitNow();
       Trace.endSection();
@@ -1308,6 +1324,26 @@
     return new ShouldShowUiResult(false, null);
   }
 
+  private static ShouldShowUiResult getShouldShowRttUi() {
+    DialerCall call = CallList.getInstance().getFirstCall();
+    if (call == null) {
+      LogUtil.i("InCallActivity.getShouldShowRttUi", "null call");
+      return new ShouldShowUiResult(false, null);
+    }
+
+    if (call.isRttCall()) {
+      LogUtil.i("InCallActivity.getShouldShowRttUi", "found rtt call");
+      return new ShouldShowUiResult(true, call);
+    }
+
+    if (call.hasSentRttUpgradeRequest()) {
+      LogUtil.i("InCallActivity.getShouldShowRttUi", "upgrading to rtt");
+      return new ShouldShowUiResult(true, call);
+    }
+
+    return new ShouldShowUiResult(false, null);
+  }
+
   private boolean showAnswerScreenFragment(FragmentTransaction transaction, DialerCall call) {
     // When rejecting a call the active call can become null in which case we should continue
     // showing the answer screen.
@@ -1347,6 +1383,7 @@
     AnswerScreen answerScreen =
         AnswerBindings.createAnswerScreen(
             call.getId(),
+            call.isRttCall(),
             call.isVideoCall(),
             isVideoUpgradeRequest,
             call.getVideoTech().isSelfManagedCamera(),
@@ -1418,6 +1455,33 @@
     return true;
   }
 
+  private boolean showRttCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
+    if (didShowRttCallScreen) {
+      // This shouldn't happen since only one RTT call is allow at same time.
+      if (!getRttCallScreen().getCallId().equals(call.getId())) {
+        LogUtil.e("InCallActivity.showRttCallScreenFragment", "RTT call id doesn't match");
+      }
+      return false;
+    }
+    RttCallScreen rttCallScreen = RttBindings.createRttCallScreen(call.getId());
+    transaction.add(R.id.main, rttCallScreen.getRttCallScreenFragment(), Tags.RTT_CALL_SCREEN);
+    Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
+    didShowRttCallScreen = true;
+    return true;
+  }
+
+  private boolean hideRttCallScreenFragment(FragmentTransaction transaction) {
+    if (!didShowRttCallScreen) {
+      return false;
+    }
+    RttCallScreen rttCallScreen = getRttCallScreen();
+    if (rttCallScreen != null) {
+      transaction.remove(rttCallScreen.getRttCallScreenFragment());
+    }
+    didShowRttCallScreen = false;
+    return true;
+  }
+
   private boolean showVideoCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
     if (didShowVideoCallScreen) {
       VideoCallScreen videoCallScreen = getVideoCallScreen();
@@ -1467,6 +1531,10 @@
     return (VideoCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.VIDEO_CALL_SCREEN);
   }
 
+  private RttCallScreen getRttCallScreen() {
+    return (RttCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.RTT_CALL_SCREEN);
+  }
+
   @Override
   public void onPseudoScreenStateChanged(boolean isOn) {
     LogUtil.i("InCallActivity.onPseudoScreenStateChanged", "isOn: " + isOn);
@@ -1499,6 +1567,11 @@
     return super.dispatchTouchEvent(event);
   }
 
+  @Override
+  public RttCallScreenDelegate newRttCallScreenDelegate(RttCallScreen videoCallScreen) {
+    return new RttCallPresenter();
+  }
+
   private static class ShouldShowUiResult {
     public final boolean shouldShow;
     public final DialerCall call;
@@ -1536,6 +1609,7 @@
     static final String INTERNATIONAL_CALL_ON_WIFI = "tag_international_call_on_wifi";
     static final String SELECT_ACCOUNT_FRAGMENT = "tag_select_account_fragment";
     static final String VIDEO_CALL_SCREEN = "tag_video_call_screen";
+    static final String RTT_CALL_SCREEN = "tag_rtt_call_screen";
     static final String POST_CHAR_DIALOG_FRAGMENT = "tag_post_char_dialog_fragment";
   }
 
diff --git a/java/com/android/incallui/ProximitySensor.java b/java/com/android/incallui/ProximitySensor.java
index f82b75d..4b03344 100644
--- a/java/com/android/incallui/ProximitySensor.java
+++ b/java/com/android/incallui/ProximitySensor.java
@@ -55,6 +55,7 @@
   private boolean dialpadVisible;
   private boolean isAttemptingVideoCall;
   private boolean isVideoCall;
+  private boolean isRttCall;
 
   public ProximitySensor(
       @NonNull Context context,
@@ -112,10 +113,14 @@
 
     DialerCall activeCall = callList.getActiveCall();
     boolean isVideoCall = activeCall != null && activeCall.isVideoCall();
+    boolean isRttCall = activeCall != null && activeCall.isRttCall();
 
-    if (isOffhook != isPhoneOffhook || this.isVideoCall != isVideoCall) {
+    if (isOffhook != isPhoneOffhook
+        || this.isVideoCall != isVideoCall
+        || this.isRttCall != isRttCall) {
       isPhoneOffhook = isOffhook;
       this.isVideoCall = isVideoCall;
+      this.isRttCall = isRttCall;
 
       orientation = AccelerometerListener.ORIENTATION_UNKNOWN;
       accelerometerListener.enable(isPhoneOffhook);
@@ -217,7 +222,8 @@
             || CallAudioState.ROUTE_SPEAKER == audioRoute
             || CallAudioState.ROUTE_BLUETOOTH == audioRoute
             || isAttemptingVideoCall
-            || isVideoCall);
+            || isVideoCall
+            || isRttCall);
 
     // We do not keep the screen off when the user is outside in-call screen and we are
     // horizontal, but we do not force it on when we become horizontal until the
diff --git a/java/com/android/incallui/RttCallPresenter.java b/java/com/android/incallui/RttCallPresenter.java
new file mode 100644
index 0000000..b90d56b
--- /dev/null
+++ b/java/com/android/incallui/RttCallPresenter.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.incallui;
+
+import android.content.Context;
+import com.android.incallui.rtt.protocol.RttCallScreen;
+import com.android.incallui.rtt.protocol.RttCallScreenDelegate;
+
+/**
+ * Logic related to the {@link RttCallScreen} and for managing changes to the RTT calling surfaces
+ * based on other user interface events and incoming events.
+ */
+public class RttCallPresenter implements RttCallScreenDelegate {
+
+  private Context appContext;
+  private RttCallScreen rttCallScreen;
+
+  @Override
+  public void initRttCallScreenDelegate(Context context, RttCallScreen rttCallScreen) {
+    this.appContext = context.getApplicationContext();
+    this.rttCallScreen = rttCallScreen;
+  }
+
+  @Override
+  public void onRttCallScreenUiReady() {}
+
+  @Override
+  public void onRttCallScreenUiUnready() {}
+}
diff --git a/java/com/android/incallui/answer/bindings/AnswerBindings.java b/java/com/android/incallui/answer/bindings/AnswerBindings.java
index 0b546db..9f4199b 100644
--- a/java/com/android/incallui/answer/bindings/AnswerBindings.java
+++ b/java/com/android/incallui/answer/bindings/AnswerBindings.java
@@ -24,6 +24,7 @@
 
   public static AnswerScreen createAnswerScreen(
       String callId,
+      boolean isRttCall,
       boolean isVideoCall,
       boolean isVideoUpgradeRequest,
       boolean isSelfManagedCamera,
@@ -31,6 +32,7 @@
       boolean hasCallOnHold) {
     return AnswerFragment.newInstance(
         callId,
+        isRttCall,
         isVideoCall,
         isVideoUpgradeRequest,
         isSelfManagedCamera,
diff --git a/java/com/android/incallui/answer/impl/AnswerFragment.java b/java/com/android/incallui/answer/impl/AnswerFragment.java
index d687b6e..8626e6d 100644
--- a/java/com/android/incallui/answer/impl/AnswerFragment.java
+++ b/java/com/android/incallui/answer/impl/AnswerFragment.java
@@ -103,6 +103,8 @@
   @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
   static final String ARG_CALL_ID = "call_id";
 
+  static final String ARG_IS_RTT_CALL = "is_rtt_call";
+
   @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
   static final String ARG_IS_VIDEO_CALL = "is_video_call";
 
@@ -344,6 +346,7 @@
 
   public static AnswerFragment newInstance(
       String callId,
+      boolean isRttCall,
       boolean isVideoCall,
       boolean isVideoUpgradeRequest,
       boolean isSelfManagedCamera,
@@ -351,6 +354,7 @@
       boolean hasCallOnHold) {
     Bundle bundle = new Bundle();
     bundle.putString(ARG_CALL_ID, Assert.isNotNull(callId));
+    bundle.putBoolean(ARG_IS_RTT_CALL, isRttCall);
     bundle.putBoolean(ARG_IS_VIDEO_CALL, isVideoCall);
     bundle.putBoolean(ARG_IS_VIDEO_UPGRADE_REQUEST, isVideoUpgradeRequest);
     bundle.putBoolean(ARG_IS_SELF_MANAGED_CAMERA, isSelfManagedCamera);
@@ -663,6 +667,7 @@
     Trace.beginSection("AnswerFragment.onCreateView");
     Bundle arguments = getArguments();
     Assert.checkState(arguments.containsKey(ARG_CALL_ID));
+    Assert.checkState(arguments.containsKey(ARG_IS_RTT_CALL));
     Assert.checkState(arguments.containsKey(ARG_IS_VIDEO_CALL));
     Assert.checkState(arguments.containsKey(ARG_IS_VIDEO_UPGRADE_REQUEST));
 
@@ -836,6 +841,11 @@
   }
 
   @Override
+  public boolean isRttCall() {
+    return getArguments().getBoolean(ARG_IS_RTT_CALL);
+  }
+
+  @Override
   public boolean isVideoCall() {
     return getArguments().getBoolean(ARG_IS_VIDEO_CALL);
   }
diff --git a/java/com/android/incallui/answer/impl/answermethod/AnswerMethodHolder.java b/java/com/android/incallui/answer/impl/answermethod/AnswerMethodHolder.java
index afa194f..0f1455c 100644
--- a/java/com/android/incallui/answer/impl/answermethod/AnswerMethodHolder.java
+++ b/java/com/android/incallui/answer/impl/answermethod/AnswerMethodHolder.java
@@ -46,4 +46,6 @@
   boolean isVideoCall();
 
   boolean isVideoUpgradeRequest();
+
+  boolean isRttCall();
 }
diff --git a/java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java b/java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java
index fe6bbbc..b5dbc0c 100644
--- a/java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java
+++ b/java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java
@@ -335,6 +335,8 @@
     }
     if (getParent().isVideoCall() || getParent().isVideoUpgradeRequest()) {
       contactPuckIcon.setImageResource(R.drawable.quantum_ic_videocam_white_24);
+    } else if (getParent().isRttCall()) {
+      contactPuckIcon.setImageResource(R.drawable.quantum_ic_call_white_24);
     } else {
       contactPuckIcon.setImageResource(R.drawable.quantum_ic_call_white_24);
     }
diff --git a/java/com/android/incallui/answer/protocol/AnswerScreen.java b/java/com/android/incallui/answer/protocol/AnswerScreen.java
index 5ad5002..f030ce9 100644
--- a/java/com/android/incallui/answer/protocol/AnswerScreen.java
+++ b/java/com/android/incallui/answer/protocol/AnswerScreen.java
@@ -24,6 +24,8 @@
 
   String getCallId();
 
+  boolean isRttCall();
+
   boolean isVideoCall();
 
   boolean isVideoUpgradeRequest();
diff --git a/java/com/android/incallui/call/DialerCall.java b/java/com/android/incallui/call/DialerCall.java
index 1785ece..cbe7c57 100644
--- a/java/com/android/incallui/call/DialerCall.java
+++ b/java/com/android/incallui/call/DialerCall.java
@@ -32,6 +32,7 @@
 import android.support.v4.os.BuildCompat;
 import android.telecom.Call;
 import android.telecom.Call.Details;
+import android.telecom.Call.RttCall;
 import android.telecom.CallAudioState;
 import android.telecom.Connection;
 import android.telecom.DisconnectCause;
@@ -263,6 +264,28 @@
         }
 
         @Override
+        public void onRttModeChanged(Call call, int mode) {
+          LogUtil.v("TelecomCallCallback.onRttModeChanged", "mode=%d", mode);
+        }
+
+        @Override
+        public void onRttRequest(Call call, int id) {
+          LogUtil.v("TelecomCallCallback.onRttRequest", "id=%d", id);
+        }
+
+        @Override
+        public void onRttInitiationFailure(Call call, int reason) {
+          LogUtil.v("TelecomCallCallback.onRttInitiationFailure", "reason=%d", reason);
+          update();
+        }
+
+        @Override
+        public void onRttStatusChanged(Call call, boolean enabled, RttCall rttCall) {
+          LogUtil.v("TelecomCallCallback.onRttStatusChanged", "enabled=%b", enabled);
+          update();
+        }
+
+        @Override
         public void onConnectionEvent(android.telecom.Call call, String event, Bundle extras) {
           LogUtil.v(
               "TelecomCallCallback.onConnectionEvent",
@@ -906,6 +929,14 @@
     return getVideoTech().isTransmittingOrReceiving() || VideoProfile.isVideo(getVideoState());
   }
 
+  public boolean isRttCall() {
+    if (BuildCompat.isAtLeastP()) {
+      return getTelecomCall().isRttActive();
+    } else {
+      return false;
+    }
+  }
+
   public boolean hasReceivedVideoUpgradeRequest() {
     return VideoUtils.hasReceivedVideoUpgradeRequest(getVideoTech().getSessionModificationState());
   }
@@ -914,6 +945,11 @@
     return VideoUtils.hasSentVideoUpgradeRequest(getVideoTech().getSessionModificationState());
   }
 
+  public boolean hasSentRttUpgradeRequest() {
+    // TODO(wangqi): Implement this.
+    return false;
+  }
+
   /**
    * Determines if the call handle is an emergency number or not and caches the result to avoid
    * repeated calls to isEmergencyNumber.
diff --git a/java/com/android/incallui/rtt/bindings/RttBindings.java b/java/com/android/incallui/rtt/bindings/RttBindings.java
new file mode 100644
index 0000000..8f9a143
--- /dev/null
+++ b/java/com/android/incallui/rtt/bindings/RttBindings.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.incallui.rtt.bindings;
+
+import com.android.incallui.rtt.impl.RttChatFragment;
+import com.android.incallui.rtt.protocol.RttCallScreen;
+
+/** Bindings for RTT module. */
+public class RttBindings {
+
+  public static RttCallScreen createRttCallScreen(String callId) {
+    return RttChatFragment.newInstance(callId);
+  }
+}
diff --git a/java/com/android/incallui/rtt/impl/AndroidManifest.xml b/java/com/android/incallui/rtt/impl/AndroidManifest.xml
index fc0705d..7f58f71 100644
--- a/java/com/android/incallui/rtt/impl/AndroidManifest.xml
+++ b/java/com/android/incallui/rtt/impl/AndroidManifest.xml
@@ -13,14 +13,5 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<manifest
-    package="com.android.incallui.rtt.impl"
-    xmlns:android="http://schemas.android.com/apk/res/android">
-  <application android:theme="@style/Theme.AppCompat">
-  <activity
-      android:name=".RttChatActivity"
-      android:exported="false"
-      android:theme="@style/DialerThemeBase.NoActionBar"
-      android:windowSoftInputMode="adjustResize"/>
-  </application>
+<manifest package="com.android.incallui.rtt.impl">
 </manifest>
diff --git a/java/com/android/incallui/rtt/impl/RttChatActivity.java b/java/com/android/incallui/rtt/impl/RttChatActivity.java
deleted file mode 100644
index 96056f7..0000000
--- a/java/com/android/incallui/rtt/impl/RttChatActivity.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.incallui.rtt.impl;
-
-import android.os.Bundle;
-import android.os.SystemClock;
-import android.support.annotation.Nullable;
-import android.support.v4.app.FragmentActivity;
-import android.view.View;
-
-/** Activity to for RTT chat window. */
-public class RttChatActivity extends FragmentActivity {
-
-  @Override
-  protected void onCreate(@Nullable Bundle savedInstanceState) {
-    super.onCreate(savedInstanceState);
-    setContentView(R.layout.activity_rtt);
-    getSupportFragmentManager()
-        .beginTransaction()
-        .add(
-            R.id.fragment_rtt,
-            RttChatFragment.newInstance("", "Jane Williamson", SystemClock.elapsedRealtime()))
-        .commit();
-    getWindow().setStatusBarColor(getColor(R.color.rtt_status_bar_color));
-    getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
-  }
-}
diff --git a/java/com/android/incallui/rtt/impl/RttChatFragment.java b/java/com/android/incallui/rtt/impl/RttChatFragment.java
index 0b0ad2a..82dce3e 100644
--- a/java/com/android/incallui/rtt/impl/RttChatFragment.java
+++ b/java/com/android/incallui/rtt/impl/RttChatFragment.java
@@ -16,21 +16,25 @@
 
 package com.android.incallui.rtt.impl;
 
+import android.app.Activity;
 import android.os.Bundle;
 import android.os.SystemClock;
+import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v4.app.Fragment;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.OnScrollListener;
+import android.telecom.CallAudioState;
 import android.text.Editable;
 import android.text.TextUtils;
 import android.text.TextWatcher;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.View.OnClickListener;
 import android.view.ViewGroup;
+import android.view.Window;
+import android.view.accessibility.AccessibilityEvent;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Chronometer;
@@ -38,11 +42,31 @@
 import android.widget.ImageButton;
 import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
+import com.android.dialer.common.Assert;
+import com.android.dialer.common.FragmentUtils;
+import com.android.dialer.common.LogUtil;
+import com.android.incallui.incall.protocol.InCallButtonUi;
+import com.android.incallui.incall.protocol.InCallButtonUiDelegate;
+import com.android.incallui.incall.protocol.InCallButtonUiDelegateFactory;
+import com.android.incallui.incall.protocol.InCallScreen;
+import com.android.incallui.incall.protocol.InCallScreenDelegate;
+import com.android.incallui.incall.protocol.InCallScreenDelegateFactory;
+import com.android.incallui.incall.protocol.PrimaryCallState;
+import com.android.incallui.incall.protocol.PrimaryInfo;
+import com.android.incallui.incall.protocol.SecondaryInfo;
 import com.android.incallui.rtt.impl.RttChatAdapter.MessageListener;
+import com.android.incallui.rtt.protocol.RttCallScreen;
+import com.android.incallui.rtt.protocol.RttCallScreenDelegate;
+import com.android.incallui.rtt.protocol.RttCallScreenDelegateFactory;
 
 /** RTT chat fragment to show chat bubbles. */
 public class RttChatFragment extends Fragment
-    implements OnClickListener, OnEditorActionListener, TextWatcher, MessageListener {
+    implements OnEditorActionListener,
+        TextWatcher,
+        MessageListener,
+        RttCallScreen,
+        InCallScreen,
+        InCallButtonUi {
 
   private static final String ARG_CALL_ID = "call_id";
   private static final String ARG_NAME_OR_NUMBER = "name_or_number";
@@ -63,27 +87,58 @@
           }
         }
       };
+  private InCallScreenDelegate inCallScreenDelegate;
+  private RttCallScreenDelegate rttCallScreenDelegate;
+  private InCallButtonUiDelegate inCallButtonUiDelegate;
+  private View endCallButton;
 
   /**
    * Create a new instance of RttChatFragment.
    *
    * @param callId call id of the RTT call.
-   * @param nameOrNumber name or number of the caller to be displayed
-   * @param sessionStartTimeMillis start time of RTT session in terms of {@link
-   *     SystemClock#elapsedRealtime}.
    * @return new RttChatFragment
    */
-  public static RttChatFragment newInstance(
-      String callId, String nameOrNumber, long sessionStartTimeMillis) {
+  public static RttChatFragment newInstance(String callId) {
     Bundle bundle = new Bundle();
     bundle.putString(ARG_CALL_ID, callId);
-    bundle.putString(ARG_NAME_OR_NUMBER, nameOrNumber);
-    bundle.putLong(ARG_SESSION_START_TIME, sessionStartTimeMillis);
+    bundle.putString(ARG_NAME_OR_NUMBER, "Jane Williamson");
+    bundle.putLong(ARG_SESSION_START_TIME, SystemClock.elapsedRealtime());
     RttChatFragment instance = new RttChatFragment();
     instance.setArguments(bundle);
     return instance;
   }
 
+  @Override
+  public void onCreate(@Nullable Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+    LogUtil.i("RttChatFragment.onCreate", null);
+    inCallButtonUiDelegate =
+        FragmentUtils.getParent(this, InCallButtonUiDelegateFactory.class)
+            .newInCallButtonUiDelegate();
+    if (savedInstanceState != null) {
+      inCallButtonUiDelegate.onRestoreInstanceState(savedInstanceState);
+    }
+  }
+
+  @Override
+  public void onViewCreated(@NonNull View view, @Nullable Bundle bundle) {
+    super.onViewCreated(view, bundle);
+    LogUtil.i("RttChatFragment.onViewCreated", null);
+
+    inCallScreenDelegate =
+        FragmentUtils.getParentUnsafe(this, InCallScreenDelegateFactory.class)
+            .newInCallScreenDelegate();
+    rttCallScreenDelegate =
+        FragmentUtils.getParentUnsafe(this, RttCallScreenDelegateFactory.class)
+            .newRttCallScreenDelegate(this);
+
+    rttCallScreenDelegate.initRttCallScreenDelegate(getContext(), this);
+
+    inCallScreenDelegate.onInCallScreenDelegateInit(this);
+    inCallScreenDelegate.onInCallScreenReady();
+    inCallButtonUiDelegate.onInCallButtonUiReady(this);
+  }
+
   @Nullable
   @Override
   public View onCreateView(
@@ -101,8 +156,20 @@
     recyclerView.setAdapter(adapter);
     recyclerView.addOnScrollListener(onScrollListener);
     submitButton = view.findViewById(R.id.rtt_chat_submit_button);
-    submitButton.setOnClickListener(this);
+    submitButton.setOnClickListener(
+        v -> {
+          adapter.submitLocalMessage();
+          isClearingInput = true;
+          editText.setText("");
+          isClearingInput = false;
+        });
     submitButton.setEnabled(false);
+    endCallButton = view.findViewById(R.id.rtt_end_call_button);
+    endCallButton.setOnClickListener(
+        v -> {
+          LogUtil.i("RttChatFragment.onClick", "end call button clicked");
+          inCallButtonUiDelegate.onEndCallClicked();
+        });
 
     String nameOrNumber = null;
     Bundle bundle = getArguments();
@@ -123,16 +190,6 @@
   }
 
   @Override
-  public void onClick(View v) {
-    if (v.getId() == R.id.rtt_chat_submit_button) {
-      adapter.submitLocalMessage();
-      isClearingInput = true;
-      editText.setText("");
-      isClearingInput = false;
-    }
-  }
-
-  @Override
   public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
     if (actionId == EditorInfo.IME_ACTION_DONE) {
       submitButton.performClick();
@@ -166,6 +223,20 @@
     recyclerView.smoothScrollToPosition(adapter.getItemCount());
   }
 
+  @Override
+  public void onStart() {
+    LogUtil.enterBlock("RttChatFragment.onStart");
+    super.onStart();
+    onRttScreenStart();
+  }
+
+  @Override
+  public void onStop() {
+    LogUtil.enterBlock("RttChatFragment.onStop");
+    super.onStop();
+    onRttScreenStop();
+  }
+
   private void hideKeyboard() {
     InputMethodManager inputMethodManager = getContext().getSystemService(InputMethodManager.class);
     if (inputMethodManager.isAcceptingText()) {
@@ -173,4 +244,116 @@
           getActivity().getCurrentFocus().getWindowToken(), 0);
     }
   }
+
+  @Override
+  public void onRttScreenStart() {
+    rttCallScreenDelegate.onRttCallScreenUiReady();
+    Activity activity = getActivity();
+    Window window = getActivity().getWindow();
+    window.setStatusBarColor(activity.getColor(R.color.rtt_status_bar_color));
+    window.setNavigationBarColor(activity.getColor(R.color.rtt_navigation_bar_color));
+    window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
+  }
+
+  @Override
+  public void onRttScreenStop() {
+    rttCallScreenDelegate.onRttCallScreenUiUnready();
+  }
+
+  @Override
+  public Fragment getRttCallScreenFragment() {
+    return this;
+  }
+
+  @Override
+  public String getCallId() {
+    return Assert.isNotNull(getArguments().getString(ARG_CALL_ID));
+  }
+
+  @Override
+  public void setPrimary(@NonNull PrimaryInfo primaryInfo) {
+    LogUtil.i("RttChatFragment.setPrimary", primaryInfo.toString());
+  }
+
+  @Override
+  public void setSecondary(@NonNull SecondaryInfo secondaryInfo) {}
+
+  @Override
+  public void setCallState(@NonNull PrimaryCallState primaryCallState) {}
+
+  @Override
+  public void setEndCallButtonEnabled(boolean enabled, boolean animate) {}
+
+  @Override
+  public void showManageConferenceCallButton(boolean visible) {}
+
+  @Override
+  public boolean isManageConferenceVisible() {
+    return false;
+  }
+
+  @Override
+  public void dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {}
+
+  @Override
+  public void showNoteSentToast() {}
+
+  @Override
+  public void updateInCallScreenColors() {}
+
+  @Override
+  public void onInCallScreenDialpadVisibilityChange(boolean isShowing) {}
+
+  @Override
+  public int getAnswerAndDialpadContainerResourceId() {
+    return 0;
+  }
+
+  @Override
+  public void showLocationUi(Fragment locationUi) {}
+
+  @Override
+  public boolean isShowingLocationUi() {
+    return false;
+  }
+
+  @Override
+  public Fragment getInCallScreenFragment() {
+    return this;
+  }
+
+  @Override
+  public void showButton(int buttonId, boolean show) {}
+
+  @Override
+  public void enableButton(int buttonId, boolean enable) {}
+
+  @Override
+  public void setEnabled(boolean on) {}
+
+  @Override
+  public void setHold(boolean on) {}
+
+  @Override
+  public void setCameraSwitched(boolean isBackFacingCamera) {}
+
+  @Override
+  public void setVideoPaused(boolean isPaused) {}
+
+  @Override
+  public void setAudioState(CallAudioState audioState) {}
+
+  @Override
+  public void updateButtonStates() {}
+
+  @Override
+  public void updateInCallButtonUiColors(int color) {}
+
+  @Override
+  public Fragment getInCallButtonUiFragment() {
+    return this;
+  }
+
+  @Override
+  public void showAudioRouteSelector() {}
 }
diff --git a/java/com/android/incallui/rtt/impl/res/layout/frag_rtt_chat.xml b/java/com/android/incallui/rtt/impl/res/layout/frag_rtt_chat.xml
index 7ba6a09..5ba9f4e 100644
--- a/java/com/android/incallui/rtt/impl/res/layout/frag_rtt_chat.xml
+++ b/java/com/android/incallui/rtt/impl/res/layout/frag_rtt_chat.xml
@@ -17,7 +17,8 @@
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="@color/dialer_theme_color">
+    android:background="@color/dialer_theme_color"
+    android:fitsSystemWindows="true">
 
   <include layout="@layout/rtt_banner"/>
 
@@ -52,6 +53,8 @@
         android:inputType="textMultiLine|text"
         android:maxLines="4"
         android:minHeight="53dp"
+        android:textColor="#DD000000"
+        android:textColorHint="#757575"
         android:textSize="16sp"/>
     <ImageButton
         android:id="@+id/rtt_chat_submit_button"
diff --git a/java/com/android/incallui/rtt/impl/res/layout/rtt_banner.xml b/java/com/android/incallui/rtt/impl/res/layout/rtt_banner.xml
index 4ce94f9..f193805 100644
--- a/java/com/android/incallui/rtt/impl/res/layout/rtt_banner.xml
+++ b/java/com/android/incallui/rtt/impl/res/layout/rtt_banner.xml
@@ -17,79 +17,61 @@
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
-    android:layout_height="56dp"
-    android:background="#FAFAFA"
+    android:layout_height="?attr/actionBarSize"
+    android:background="#F305228F"
     android:elevation="3dp">
   <ImageButton
-      android:id="@+id/rtt_back"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
+      android:id="@+id/rtt_end_call_button"
+      android:layout_width="32dp"
+      android:layout_height="32dp"
       android:layout_marginStart="16dp"
       android:layout_alignParentStart="true"
       android:layout_centerVertical="true"
       android:background="@android:color/transparent"
-      android:contentDescription="@string/content_description_rtt_back_button"
-      android:src="@drawable/quantum_ic_arrow_back_vd_theme_24"
-      android:tint="#DF000000"/>
+      android:contentDescription="@string/incall_content_description_end_call"
+      android:scaleType="fitXY"
+      android:src="@drawable/quantum_ic_call_end_vd_theme_24"
+      android:tint="#FFDF0000"/>
   <LinearLayout
-      android:layout_width="wrap_content"
+      android:layout_width="260dp"
       android:layout_height="match_parent"
       android:layout_marginTop="8dp"
       android:layout_marginBottom="8dp"
       android:layout_marginStart="32dp"
-      android:layout_toEndOf="@id/rtt_back"
+      android:layout_toEndOf="@id/rtt_end_call_button"
       android:orientation="vertical">
     <TextView
         android:id="@+id/rtt_name_or_number"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
         android:fontFamily="sans-serif-medium"
         android:includeFontPadding="false"
-        android:textColor="#DD000000"
+        android:textColor="#FFFFFF"
         android:textSize="20sp"
         tools:text="Bruce Graham"/>
     <Chronometer
         android:id="@+id/rtt_timer"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
         android:fontFamily="sans-serif-medium"
         android:includeFontPadding="false"
-        android:textColor="#DD000000"
+        android:textColor="#FFFFFF"
         android:textSize="14sp"
         tools:text="00:09"/>
   </LinearLayout>
   <ImageButton
-      android:id="@+id/rtt_hang_up_button"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_marginEnd="16dp"
+      android:id="@+id/rtt_overflow_button"
+      android:layout_width="32dp"
+      android:layout_height="32dp"
+      android:layout_marginEnd="12dp"
       android:layout_alignParentEnd="true"
       android:layout_centerVertical="true"
       android:background="@android:color/transparent"
-      android:contentDescription="@string/incall_content_description_end_call"
-      android:src="@drawable/quantum_ic_call_end_vd_theme_24"
-      android:tint="#FFDF0000"/>
-  <ImageButton
-      android:id="@+id/rtt_speaker_button"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_marginEnd="24dp"
-      android:layout_centerVertical="true"
-      android:layout_toStartOf="@id/rtt_hang_up_button"
-      android:background="@android:color/transparent"
-      android:contentDescription="@string/incall_content_description_speaker"
-      android:src="@drawable/quantum_ic_volume_up_vd_theme_24"
-      android:tint="#DD000000"/>
-  <ImageButton
-      android:id="@+id/rtt_mic_button"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_marginEnd="24dp"
-      android:layout_centerVertical="true"
-      android:layout_toStartOf="@id/rtt_speaker_button"
-      android:background="@android:color/transparent"
-      android:contentDescription="@string/incall_content_description_unmuted"
-      android:src="@drawable/quantum_ic_mic_off_vd_theme_24"
-      android:tint="#DD000000"/>
+      android:contentDescription="@string/content_description_overflow"
+      android:scaleType="fitXY"
+      android:src="@drawable/quantum_ic_more_vert_vd_theme_24"
+      android:tint="#FFFFFF"/>
 
 </RelativeLayout>
\ No newline at end of file
diff --git a/java/com/android/incallui/rtt/impl/res/values/colors.xml b/java/com/android/incallui/rtt/impl/res/values/colors.xml
index 402cac4..c25ad21 100644
--- a/java/com/android/incallui/rtt/impl/res/values/colors.xml
+++ b/java/com/android/incallui/rtt/impl/res/values/colors.xml
@@ -15,5 +15,6 @@
   ~ limitations under the License
   -->
 <resources>
-  <color name="rtt_status_bar_color">#E0E0E0</color>
+  <color name="rtt_status_bar_color">#03165C</color>
+  <color name="rtt_navigation_bar_color">#FAFAFA</color>
 </resources>
\ No newline at end of file
diff --git a/java/com/android/incallui/rtt/impl/res/values/strings.xml b/java/com/android/incallui/rtt/impl/res/values/strings.xml
index 523abdc..0b9eb71 100644
--- a/java/com/android/incallui/rtt/impl/res/values/strings.xml
+++ b/java/com/android/incallui/rtt/impl/res/values/strings.xml
@@ -18,9 +18,6 @@
   <!-- Content description for submit chat input button. [CHAR LIMIT=NONE] -->
   <string name="content_description_rtt_check_button">Go ahead</string>
 
-  <!-- Content description for navigate back button on RTT chat window. [CHAR LIMIT=NONE] -->
-  <string name="content_description_rtt_back_button">Back</string>
-
   <!-- Hint text for input box. [CHAR LIMIT=NONE] -->
   <string name="rtt_input_hint">Type a message</string>
 
diff --git a/java/com/android/incallui/rtt/impl/res/layout/activity_rtt.xml b/java/com/android/incallui/rtt/protocol/AndroidManifest.xml
similarity index 62%
rename from java/com/android/incallui/rtt/impl/res/layout/activity_rtt.xml
rename to java/com/android/incallui/rtt/protocol/AndroidManifest.xml
index b48e8d4..52514a5 100644
--- a/java/com/android/incallui/rtt/impl/res/layout/activity_rtt.xml
+++ b/java/com/android/incallui/rtt/protocol/AndroidManifest.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2018 The Android Open Source Project
   ~
@@ -14,13 +13,10 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-  <FrameLayout
-      android:id="@+id/fragment_rtt"
-      android:layout_width="match_parent"
-      android:layout_height="match_parent"/>
 
-</LinearLayout>
\ No newline at end of file
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.incallui.rtt.protocol">
+  <uses-sdk
+      android:minSdkVersion="23"
+      android:targetSdkVersion="26"/>
+</manifest>
\ No newline at end of file
diff --git a/java/com/android/incallui/rtt/protocol/RttCallScreen.java b/java/com/android/incallui/rtt/protocol/RttCallScreen.java
new file mode 100644
index 0000000..afacbae
--- /dev/null
+++ b/java/com/android/incallui/rtt/protocol/RttCallScreen.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.incallui.rtt.protocol;
+
+import android.support.v4.app.Fragment;
+
+/** Interface for call RTT call module. */
+public interface RttCallScreen {
+
+  void onRttScreenStart();
+
+  void onRttScreenStop();
+
+  Fragment getRttCallScreenFragment();
+
+  String getCallId();
+}
diff --git a/java/com/android/incallui/rtt/protocol/RttCallScreenDelegate.java b/java/com/android/incallui/rtt/protocol/RttCallScreenDelegate.java
new file mode 100644
index 0000000..e29c43d
--- /dev/null
+++ b/java/com/android/incallui/rtt/protocol/RttCallScreenDelegate.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.incallui.rtt.protocol;
+
+import android.content.Context;
+
+/** Callbacks from the module out to the container. */
+public interface RttCallScreenDelegate {
+
+  void initRttCallScreenDelegate(Context context, RttCallScreen rttCallScreen);
+
+  void onRttCallScreenUiReady();
+
+  void onRttCallScreenUiUnready();
+}
diff --git a/java/com/android/incallui/rtt/protocol/RttCallScreenDelegateFactory.java b/java/com/android/incallui/rtt/protocol/RttCallScreenDelegateFactory.java
new file mode 100644
index 0000000..0dbcc91
--- /dev/null
+++ b/java/com/android/incallui/rtt/protocol/RttCallScreenDelegateFactory.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.incallui.rtt.protocol;
+
+/** Callbacks from the module out to the container. */
+public interface RttCallScreenDelegateFactory {
+
+  RttCallScreenDelegate newRttCallScreenDelegate(RttCallScreen rttCallScreen);
+}