RttChatbot.java revision aeece4ec4184b76e0ac2e8a012af05638ad866f6
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
17package com.android.server.telecom.testapps;
18
19import android.content.Context;
20import android.os.Handler;
21import android.os.HandlerThread;
22import android.os.Looper;
23import android.os.Message;
24import android.os.ParcelFileDescriptor;
25import android.telecom.Connection;
26import android.telecom.Log;
27
28import java.io.FileInputStream;
29import java.io.FileOutputStream;
30import java.io.IOException;
31import java.io.InputStreamReader;
32import java.io.OutputStreamWriter;
33import java.util.Random;
34
35public 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 = mRttTextStream.read();
120                if (charsReceived == null) {
121                    if (Thread.currentThread().isInterrupted()) {
122                        Log.w(LOG_TAG, "Thread interrupted");
123                        break;
124                    }
125                    Log.w(LOG_TAG, "Stream closed");
126                    break;
127                }
128                if (charsReceived.length() == 0) {
129                    continue;
130                }
131                mHandler.obtainMessage(APPEND_TO_INPUT_BUFFER, charsReceived)
132                        .sendToTarget();
133            }
134        }, "RttChatbotReceiver");
135        mReceiverThread.start();
136    }
137
138    public void stop() {
139        if (mSenderThread != null && mSenderThread.isAlive()) {
140            mSenderThread.quit();
141        }
142        if (mReceiverThread != null && mReceiverThread.isAlive()) {
143            mReceiverThread.interrupt();
144        }
145    }
146}
147