1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.dialer.simulator.impl; 18 19 import android.annotation.TargetApi; 20 import android.os.Handler; 21 import android.os.HandlerThread; 22 import android.os.Looper; 23 import android.support.annotation.MainThread; 24 import android.telecom.Connection.RttTextStream; 25 import com.android.dialer.common.Assert; 26 import com.android.dialer.common.LogUtil; 27 import com.android.incallui.rtt.protocol.Constants; 28 import java.io.IOException; 29 import java.util.ArrayList; 30 import java.util.List; 31 import java.util.Random; 32 33 /** Chat bot to generate remote RTT chat messages. */ 34 @TargetApi(28) 35 class RttChatBot { 36 37 interface Callback { type(String text)38 void type(String text); 39 } 40 41 private static final int START_SENDING = 1; 42 private static final int SEND_MESSAGE = 2; 43 44 private static final String[] CANDIDATE_MESSAGES = 45 new String[] { 46 "To RTT or not to RTT, that is the question...", 47 "Making TTY great again!", 48 "I would be more comfortable with real \"Thyme\" chatting." 49 + " I don't know how to end this pun", 50 "お疲れ様でした", 51 "The FCC has mandated that I respond... I will do so begrudgingly", 52 "" 53 }; 54 55 private final MessageHandler messageHandler; 56 private final HandlerThread handlerThread; 57 RttChatBot(RttTextStream rttTextStream)58 RttChatBot(RttTextStream rttTextStream) { 59 handlerThread = new HandlerThread("RttChatBot"); 60 handlerThread.start(); 61 messageHandler = new MessageHandler(handlerThread.getLooper(), rttTextStream); 62 } 63 64 @MainThread start()65 void start() { 66 Assert.isMainThread(); 67 LogUtil.enterBlock("RttChatBot.start"); 68 messageHandler.sendEmptyMessage(START_SENDING); 69 } 70 71 @MainThread stop()72 void stop() { 73 Assert.isMainThread(); 74 LogUtil.enterBlock("RttChatBot.stop"); 75 if (handlerThread != null && handlerThread.isAlive()) { 76 handlerThread.quit(); 77 } 78 } 79 80 private static class MessageHandler extends Handler { 81 private final RttTextStream rttTextStream; 82 private final Random random = new Random(); 83 private final List<String> messageQueue = new ArrayList<>(); 84 private int currentTypingPosition = -1; 85 private String currentTypingMessage = null; 86 MessageHandler(Looper looper, RttTextStream rttTextStream)87 MessageHandler(Looper looper, RttTextStream rttTextStream) { 88 super(looper); 89 this.rttTextStream = rttTextStream; 90 } 91 92 @Override handleMessage(android.os.Message msg)93 public void handleMessage(android.os.Message msg) { 94 switch (msg.what) { 95 case START_SENDING: 96 sendMessage(obtainMessage(SEND_MESSAGE, nextTyping())); 97 break; 98 case SEND_MESSAGE: 99 String message = (String) msg.obj; 100 try { 101 rttTextStream.write(message); 102 } catch (IOException e) { 103 LogUtil.e("RttChatBot.MessageHandler", "write message", e); 104 } 105 if (Constants.BUBBLE_BREAKER.equals(message)) { 106 // Wait 1-11s between two messages. 107 sendMessageDelayed( 108 obtainMessage(SEND_MESSAGE, nextTyping()), 1000 * (1 + random.nextInt(10))); 109 } else { 110 // Wait up to 2s between typing. 111 sendMessageDelayed(obtainMessage(SEND_MESSAGE, nextTyping()), 200 * random.nextInt(10)); 112 } 113 break; 114 default: // fall out 115 } 116 } 117 nextTyping()118 private String nextTyping() { 119 if (currentTypingPosition < 0 || currentTypingMessage == null) { 120 if (messageQueue.isEmpty()) { 121 String text = CANDIDATE_MESSAGES[random.nextInt(CANDIDATE_MESSAGES.length)]; 122 messageQueue.add(text); 123 } 124 currentTypingMessage = messageQueue.remove(0); 125 currentTypingPosition = 0; 126 } 127 if (currentTypingPosition < currentTypingMessage.length()) { 128 int size = random.nextInt(currentTypingMessage.length() - currentTypingPosition + 1); 129 String messageToType = 130 currentTypingMessage.substring(currentTypingPosition, currentTypingPosition + size); 131 currentTypingPosition = currentTypingPosition + size; 132 return messageToType; 133 } else { 134 currentTypingPosition = -1; 135 currentTypingMessage = null; 136 return Constants.BUBBLE_BREAKER; 137 } 138 } 139 } 140 } 141