Implement read/write text stream to RttCall.

This change also:

1. Add simulator support of RTT request during call (always accept at this moment, will add random accept/decline in the future)
2. Fix bugs of putting RTT call in background and back to call

Bug: 67596257
Test: Simulator
PiperOrigin-RevId: 185920527
Change-Id: I51016fa6cf1ccc8a5a21335f9dacf286ae393706
diff --git a/java/com/android/incallui/RttCallPresenter.java b/java/com/android/incallui/RttCallPresenter.java
index b90d56b..939c9d0 100644
--- a/java/com/android/incallui/RttCallPresenter.java
+++ b/java/com/android/incallui/RttCallPresenter.java
@@ -16,28 +16,145 @@
 
 package com.android.incallui;
 
-import android.content.Context;
+import android.annotation.TargetApi;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.telecom.Call.RttCall;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.common.concurrent.ThreadUtil;
+import com.android.incallui.InCallPresenter.InCallState;
+import com.android.incallui.InCallPresenter.InCallStateListener;
+import com.android.incallui.call.CallList;
+import com.android.incallui.call.DialerCall;
 import com.android.incallui.rtt.protocol.RttCallScreen;
 import com.android.incallui.rtt.protocol.RttCallScreenDelegate;
+import java.io.IOException;
 
 /**
  * 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 {
+@TargetApi(28)
+public class RttCallPresenter implements RttCallScreenDelegate, InCallStateListener {
 
-  private Context appContext;
   private RttCallScreen rttCallScreen;
+  private RttCall rttCall;
+  private HandlerThread handlerThread;
+  private RemoteMessageHandler remoteMessageHandler;
 
   @Override
-  public void initRttCallScreenDelegate(Context context, RttCallScreen rttCallScreen) {
-    this.appContext = context.getApplicationContext();
+  public void initRttCallScreenDelegate(RttCallScreen rttCallScreen) {
     this.rttCallScreen = rttCallScreen;
   }
 
   @Override
-  public void onRttCallScreenUiReady() {}
+  public void onLocalMessage(String message) {
+    if (rttCall == null) {
+      LogUtil.w("RttCallPresenter.onLocalMessage", "Rtt Call is not started yet");
+      return;
+    }
+    remoteMessageHandler.writeMessage(message);
+  }
 
   @Override
-  public void onRttCallScreenUiUnready() {}
+  public void onRttCallScreenUiReady() {
+    LogUtil.enterBlock("RttCallPresenter.onRttCallScreenUiReady");
+    InCallPresenter.getInstance().addListener(this);
+    startListenOnRemoteMessage();
+  }
+
+  @Override
+  public void onRttCallScreenUiUnready() {
+    LogUtil.enterBlock("RttCallPresenter.onRttCallScreenUiUnready");
+    InCallPresenter.getInstance().removeListener(this);
+    stopListenOnRemoteMessage();
+  }
+
+  @Override
+  public void onStateChange(InCallState oldState, InCallState newState, CallList callList) {
+    LogUtil.enterBlock("RttCallPresenter.onStateChange");
+    if (newState == InCallState.INCALL) {
+      startListenOnRemoteMessage();
+    }
+  }
+
+  private void startListenOnRemoteMessage() {
+    DialerCall call = CallList.getInstance().getActiveCall();
+    if (call == null) {
+      LogUtil.i("RttCallPresenter.startListenOnRemoteMessage", "call is active yet");
+      return;
+    }
+    rttCall = call.getRttCall();
+    if (rttCall == null) {
+      LogUtil.i("RttCallPresenter.startListenOnRemoteMessage", "RTT Call is not started yet");
+      return;
+    }
+    if (handlerThread != null && handlerThread.isAlive()) {
+      LogUtil.i("RttCallPresenter.startListenOnRemoteMessage", "already running");
+      return;
+    }
+    handlerThread = new HandlerThread("RttCallRemoteMessageHandler");
+    handlerThread.start();
+    remoteMessageHandler =
+        new RemoteMessageHandler(handlerThread.getLooper(), rttCall, rttCallScreen);
+    remoteMessageHandler.start();
+  }
+
+  private void stopListenOnRemoteMessage() {
+    if (handlerThread != null && handlerThread.isAlive()) {
+      handlerThread.quit();
+    }
+  }
+
+  private static class RemoteMessageHandler extends Handler {
+    private static final int START = 1;
+    private static final int READ_MESSAGE = 2;
+    private static final int WRITE_MESSAGE = 3;
+
+    private final RttCall rttCall;
+    private final RttCallScreen rttCallScreen;
+
+    RemoteMessageHandler(Looper looper, RttCall rttCall, RttCallScreen rttCallScreen) {
+      super(looper);
+      this.rttCall = rttCall;
+      this.rttCallScreen = rttCallScreen;
+    }
+
+    @Override
+    public void handleMessage(android.os.Message msg) {
+      switch (msg.what) {
+        case START:
+          sendEmptyMessage(READ_MESSAGE);
+          break;
+        case READ_MESSAGE:
+          try {
+            final String message = rttCall.readImmediately();
+            if (message != null) {
+              ThreadUtil.postOnUiThread(() -> rttCallScreen.onRemoteMessage(message));
+            }
+          } catch (IOException e) {
+            LogUtil.e("RttCallPresenter.RemoteMessageHandler.handleMessage", "read message", e);
+          }
+          sendEmptyMessageDelayed(READ_MESSAGE, 200);
+          break;
+        case WRITE_MESSAGE:
+          try {
+            rttCall.write((String) msg.obj);
+          } catch (IOException e) {
+            LogUtil.e("RttCallPresenter.RemoteMessageHandler.handleMessage", "write message", e);
+          }
+          break;
+        default: // fall out
+      }
+    }
+
+    void start() {
+      sendEmptyMessage(START);
+    }
+
+    void writeMessage(String message) {
+      sendMessage(obtainMessage(WRITE_MESSAGE, message));
+    }
+  }
 }