1 /* 2 * Copyright (C) 2017 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.server.telecom.testapps; 18 19 import android.content.Context; 20 import android.os.Handler; 21 import android.os.HandlerThread; 22 import android.os.Looper; 23 import android.os.Message; 24 import android.os.ParcelFileDescriptor; 25 import android.telecom.Connection; 26 import android.telecom.Log; 27 28 import java.io.FileInputStream; 29 import java.io.FileOutputStream; 30 import java.io.IOException; 31 import java.io.InputStreamReader; 32 import java.io.OutputStreamWriter; 33 import java.util.Random; 34 35 public class RttChatbot { 36 private static final String LOG_TAG = RttChatbot.class.getSimpleName(); 37 private static final long PER_CHARACTER_DELAY_MS = 100; 38 private static final long MSG_WAIT_DELAY_MS = 3999; 39 private static final double ONE_LINER_FREQUENCY = 0.1; 40 private static final String REPLY_PREFIX = "You said: "; 41 42 private static final int BEGIN_SEND_REPLY_MESSAGE = 1; 43 private static final int SEND_CHARACTER = 2; 44 private static final int APPEND_TO_INPUT_BUFFER = 3; 45 46 private final Connection.RttTextStream mRttTextStream; 47 private final Random mRandom = new Random(); 48 private final String[] mOneLiners; 49 private Handler mHandler; 50 private HandlerThread mSenderThread; 51 private Thread mReceiverThread; 52 53 private final class ReplyHandler extends Handler { 54 private StringBuilder mInputSoFar; 55 56 public ReplyHandler(Looper looper) { 57 super(looper); 58 } 59 60 @Override 61 public void handleMessage(Message msg) { 62 switch (msg.what) { 63 case BEGIN_SEND_REPLY_MESSAGE: 64 removeMessages(SEND_CHARACTER); 65 sendReplyMessage(); 66 break; 67 case SEND_CHARACTER: 68 try { 69 mRttTextStream.write((String) msg.obj); 70 } catch (IOException e) { 71 } 72 break; 73 case APPEND_TO_INPUT_BUFFER: 74 removeMessages(BEGIN_SEND_REPLY_MESSAGE); 75 sendEmptyMessageDelayed(BEGIN_SEND_REPLY_MESSAGE, MSG_WAIT_DELAY_MS); 76 String toAppend = (String) msg.obj; 77 if (mInputSoFar == null) { 78 mInputSoFar = new StringBuilder(toAppend); 79 } else { 80 mInputSoFar.append(toAppend); 81 } 82 Log.d(LOG_TAG, "Got %s to append, total text now %s", 83 toAppend, mInputSoFar.toString()); 84 break; 85 } 86 } 87 88 private void sendReplyMessage() { 89 String messageToSend; 90 if (mRandom.nextDouble() < ONE_LINER_FREQUENCY) { 91 messageToSend = mOneLiners[mRandom.nextInt(mOneLiners.length)]; 92 } else { 93 messageToSend = REPLY_PREFIX + mInputSoFar.toString(); 94 } 95 mInputSoFar = null; 96 Log.i(LOG_TAG, "Begin send reply message: %s", messageToSend); 97 int[] charsToSend = messageToSend.codePoints().toArray(); 98 for (int i = 0; i < charsToSend.length; i++) { 99 Message msg = obtainMessage(SEND_CHARACTER, 100 new String(new int[] {charsToSend[i]}, 0, 1)); 101 sendMessageDelayed(msg, PER_CHARACTER_DELAY_MS * i); 102 } 103 } 104 } 105 106 public RttChatbot(Context context, Connection.RttTextStream textStream) { 107 mOneLiners = context.getResources().getStringArray(R.array.rtt_reply_one_liners); 108 mRttTextStream = textStream; 109 } 110 111 public void start() { 112 Log.i(LOG_TAG, "Starting RTT chatbot."); 113 HandlerThread ht = new HandlerThread("RttChatbotSender"); 114 ht.start(); 115 mSenderThread = ht; 116 mHandler = new ReplyHandler(ht.getLooper()); 117 mReceiverThread = new Thread(() -> { 118 while (true) { 119 String charsReceived; 120 try { 121 charsReceived = mRttTextStream.read(); 122 } catch (IOException e) { 123 break; 124 } 125 if (charsReceived == null) { 126 if (Thread.currentThread().isInterrupted()) { 127 Log.w(LOG_TAG, "Thread interrupted"); 128 break; 129 } 130 Log.w(LOG_TAG, "Stream closed"); 131 break; 132 } 133 if (charsReceived.length() == 0) { 134 continue; 135 } 136 mHandler.obtainMessage(APPEND_TO_INPUT_BUFFER, charsReceived) 137 .sendToTarget(); 138 } 139 }, "RttChatbotReceiver"); 140 mReceiverThread.start(); 141 } 142 143 public void stop() { 144 if (mSenderThread != null && mSenderThread.isAlive()) { 145 mSenderThread.quit(); 146 } 147 if (mReceiverThread != null && mReceiverThread.isAlive()) { 148 mReceiverThread.interrupt(); 149 } 150 } 151 } 152