Move RttChatBot to simulator.

Bug: 67596257
Test: none
PiperOrigin-RevId: 185561470
Change-Id: I96755cc76e2a1cba65cd496d74593cdd1dedddae
diff --git a/java/com/android/dialer/simulator/impl/RttChatBot.java b/java/com/android/dialer/simulator/impl/RttChatBot.java
new file mode 100644
index 0000000..9c2989a
--- /dev/null
+++ b/java/com/android/dialer/simulator/impl/RttChatBot.java
@@ -0,0 +1,139 @@
+/*
+ * 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.dialer.simulator.impl;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.support.annotation.MainThread;
+import android.telecom.Connection.RttTextStream;
+import com.android.dialer.common.Assert;
+import com.android.dialer.common.LogUtil;
+import com.android.incallui.rtt.protocol.Constants;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+/** Chat bot to generate remote RTT chat messages. */
+public class RttChatBot {
+
+  interface Callback {
+    void type(String text);
+  }
+
+  private static final int START_SENDING = 1;
+  private static final int SEND_MESSAGE = 2;
+
+  private static final String[] CANDIDATE_MESSAGES =
+      new String[] {
+        "To RTT or not to RTT, that is the question...",
+        "Making TTY great again!",
+        "I would be more comfortable with real \"Thyme\" chatting."
+            + " I don't know how to end this pun",
+        "お疲れ様でした",
+        "The FCC has mandated that I respond... I will do so begrudgingly",
+        "😂😂😂💯"
+      };
+
+  private final MessageHandler messageHandler;
+  private final HandlerThread handlerThread;
+
+  RttChatBot(RttTextStream rttTextStream) {
+    handlerThread = new HandlerThread("RttChatBot");
+    handlerThread.start();
+    messageHandler = new MessageHandler(handlerThread.getLooper(), rttTextStream);
+  }
+
+  @MainThread
+  public void start() {
+    Assert.isMainThread();
+    LogUtil.enterBlock("RttChatBot.start");
+    messageHandler.sendEmptyMessage(START_SENDING);
+  }
+
+  @MainThread
+  public void stop() {
+    Assert.isMainThread();
+    LogUtil.enterBlock("RttChatBot.stop");
+    if (handlerThread != null && handlerThread.isAlive()) {
+      handlerThread.quit();
+    }
+  }
+
+  private static class MessageHandler extends Handler {
+    private final RttTextStream rttTextStream;
+    private final Random random = new Random();
+    private final List<String> messageQueue = new ArrayList<>();
+    private int currentTypingPosition = -1;
+    private String currentTypingMessage = null;
+
+    MessageHandler(Looper looper, RttTextStream rttTextStream) {
+      super(looper);
+      this.rttTextStream = rttTextStream;
+    }
+
+    @Override
+    public void handleMessage(android.os.Message msg) {
+      switch (msg.what) {
+        case START_SENDING:
+          sendMessage(obtainMessage(SEND_MESSAGE, nextTyping()));
+          break;
+        case SEND_MESSAGE:
+          String message = (String) msg.obj;
+          LogUtil.w("test", "type: %s, to stream: %s", message, rttTextStream);
+          try {
+            rttTextStream.write(message);
+          } catch (IOException e) {
+            LogUtil.e("RttChatBot.MessageHandler", "write message", e);
+          }
+          if (Constants.BUBBLE_BREAKER.equals(message)) {
+            // Wait 1-11s between two messages.
+            sendMessageDelayed(
+                obtainMessage(SEND_MESSAGE, nextTyping()), 1000 * (1 + random.nextInt(10)));
+          } else {
+            // Wait up to 2s between typing.
+            sendMessageDelayed(obtainMessage(SEND_MESSAGE, nextTyping()), 200 * random.nextInt(10));
+          }
+          break;
+        default: // fall out
+      }
+    }
+
+    private String nextTyping() {
+      if (currentTypingPosition < 0 || currentTypingMessage == null) {
+        if (messageQueue.isEmpty()) {
+          String text = CANDIDATE_MESSAGES[random.nextInt(CANDIDATE_MESSAGES.length)];
+          messageQueue.add(text);
+        }
+        currentTypingMessage = messageQueue.remove(0);
+        currentTypingPosition = 0;
+      }
+      if (currentTypingPosition < currentTypingMessage.length()) {
+        int size = random.nextInt(currentTypingMessage.length() - currentTypingPosition + 1);
+        String messageToType =
+            currentTypingMessage.substring(currentTypingPosition, currentTypingPosition + size);
+        currentTypingPosition = currentTypingPosition + size;
+        return messageToType;
+      } else {
+        currentTypingPosition = -1;
+        currentTypingMessage = null;
+        return Constants.BUBBLE_BREAKER;
+      }
+    }
+  }
+}
diff --git a/java/com/android/incallui/rtt/impl/RttChatAdapter.java b/java/com/android/incallui/rtt/impl/RttChatAdapter.java
index 1db4c6b..1ea7f31 100644
--- a/java/com/android/incallui/rtt/impl/RttChatAdapter.java
+++ b/java/com/android/incallui/rtt/impl/RttChatAdapter.java
@@ -17,19 +17,15 @@
 package com.android.incallui.rtt.impl;
 
 import android.content.Context;
-import android.support.annotation.MainThread;
 import android.support.v7.widget.RecyclerView;
 import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import com.android.dialer.common.Assert;
 import com.android.dialer.common.LogUtil;
-import com.android.dialer.common.concurrent.ThreadUtil;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-import java.util.Random;
 
 /** Adapter class for holding RTT chat data. */
 public class RttChatAdapter extends RecyclerView.Adapter<RttChatMessageViewHolder> {
@@ -42,13 +38,11 @@
   private final List<RttChatMessage> rttMessages = new ArrayList<>();
   private int lastIndexOfLocalMessage = -1;
   private int lastIndexOfRemoteMessage = -1;
-  private final TypeBot typeBot;
   private final MessageListener messageListener;
 
   RttChatAdapter(Context context, MessageListener listener) {
     this.context = context;
     this.messageListener = listener;
-    typeBot = new TypeBot(text -> ThreadUtil.postOnUiThread(() -> addRemoteMessage(text)));
   }
 
   @Override
@@ -133,7 +127,6 @@
     rttMessages.get(lastIndexOfLocalMessage).finish();
     notifyItemChanged(lastIndexOfLocalMessage);
     lastIndexOfLocalMessage = -1;
-    startChatBot();
   }
 
   void addRemoteMessage(String message) {
@@ -146,73 +139,4 @@
       messageListener.newMessageAdded();
     }
   }
-
-  private void startChatBot() {
-    typeBot.scheduleMessage();
-  }
-
-  // TODO(wangqi): Move this out of this class once a bug is fixed.
-  private static class TypeBot {
-    interface Callback {
-      void type(String text);
-    }
-
-    private static final String[] CANDIDATE_MESSAGES =
-        new String[] {
-          "To RTT or not to RTT, that is the question...",
-          "Making TTY great again!",
-          "I would be more comfortable with real \"Thyme\" chatting."
-              + " I don't know how to end this pun",
-          "お疲れ様でした",
-          "The FCC has mandated that I respond... I will do so begrudgingly",
-          "😂😂😂💯"
-        };
-    private final Random random = new Random();
-    private final Callback callback;
-    private final List<String> messageQueue = new ArrayList<>();
-    private int currentTypingPosition = -1;
-    private String currentTypingMessage = null;
-
-    TypeBot(Callback callback) {
-      this.callback = callback;
-    }
-
-    @MainThread
-    public void scheduleMessage() {
-      Assert.isMainThread();
-      if (random.nextDouble() < 0.5) {
-        return;
-      }
-
-      String text = CANDIDATE_MESSAGES[random.nextInt(CANDIDATE_MESSAGES.length)];
-      messageQueue.add(text);
-      typeMessage();
-    }
-
-    @MainThread
-    private void typeMessage() {
-      Assert.isMainThread();
-      if (currentTypingPosition < 0 || currentTypingMessage == null) {
-        if (messageQueue.size() <= 0) {
-          return;
-        }
-        currentTypingMessage = messageQueue.remove(0);
-        currentTypingPosition = 0;
-      }
-      if (currentTypingPosition < currentTypingMessage.length()) {
-        int size = random.nextInt(currentTypingMessage.length() - currentTypingPosition + 1);
-        callback.type(
-            currentTypingMessage.substring(currentTypingPosition, currentTypingPosition + size));
-        currentTypingPosition = currentTypingPosition + size;
-        // Wait up to 2s between typing.
-        ThreadUtil.postDelayedOnUiThread(this::typeMessage, 200 * random.nextInt(10));
-      } else {
-        callback.type(RttChatMessage.BUBBLE_BREAKER);
-        currentTypingPosition = -1;
-        currentTypingMessage = null;
-        // Wait 1-11s between two messages.
-        ThreadUtil.postDelayedOnUiThread(this::typeMessage, 1000 * (1 + random.nextInt(10)));
-      }
-    }
-  }
 }
diff --git a/java/com/android/incallui/rtt/impl/RttChatMessage.java b/java/com/android/incallui/rtt/impl/RttChatMessage.java
index 85b0451..b36da77 100644
--- a/java/com/android/incallui/rtt/impl/RttChatMessage.java
+++ b/java/com/android/incallui/rtt/impl/RttChatMessage.java
@@ -19,6 +19,7 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.text.TextWatcher;
+import com.android.incallui.rtt.protocol.Constants;
 import com.google.common.base.Splitter;
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -27,8 +28,7 @@
 /** Message class that holds one RTT chat content. */
 final class RttChatMessage {
 
-  static final String BUBBLE_BREAKER = "\n\n";
-  private static final Splitter SPLITTER = Splitter.on(BUBBLE_BREAKER);
+  private static final Splitter SPLITTER = Splitter.on(Constants.BUBBLE_BREAKER);
 
   boolean isRemote;
   public boolean hasAvatar;
@@ -108,7 +108,7 @@
       firstMessage.isRemote = true;
     }
     firstMessage.append(firstMessageContent);
-    if (splitText.hasNext() || text.endsWith(BUBBLE_BREAKER)) {
+    if (splitText.hasNext() || text.endsWith(Constants.BUBBLE_BREAKER)) {
       firstMessage.finish();
     }
     messageList.add(firstMessage);
diff --git a/java/com/android/incallui/rtt/protocol/Constants.java b/java/com/android/incallui/rtt/protocol/Constants.java
new file mode 100644
index 0000000..5806bba
--- /dev/null
+++ b/java/com/android/incallui/rtt/protocol/Constants.java
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+/** Constants for RTT call. */
+public interface Constants {
+
+  /** String used to break bubble, which means one RTT message is complete. */
+  String BUBBLE_BREAKER = "\n\n";
+}