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.app.Activity; 20import android.os.Bundle; 21import android.os.Handler; 22import android.os.Looper; 23import android.os.Message; 24import android.telecom.Call; 25import android.telecom.Log; 26import android.text.Editable; 27import android.text.TextWatcher; 28import android.view.View; 29import android.widget.AdapterView; 30import android.widget.ArrayAdapter; 31import android.widget.Button; 32import android.widget.EditText; 33import android.widget.Spinner; 34import android.widget.TextView; 35import android.widget.Toast; 36 37import java.io.IOException; 38import java.io.InputStreamReader; 39import java.io.OutputStreamWriter; 40 41public class TestRttActivity extends Activity { 42 private static final String LOG_TAG = TestRttActivity.class.getSimpleName(); 43 private static final long NEWLINE_DELAY_MILLIS = 3000; 44 45 private static final int UPDATE_RECEIVED_TEXT = 1; 46 private static final int UPDATE_SENT_TEXT = 2; 47 private static final int RECEIVED_MESSAGE_GAP = 3; 48 private static final int SENT_MESSAGE_GAP = 4; 49 50 private TextView mReceivedText; 51 private TextView mSentText; 52 private EditText mTypingBox; 53 54 private TestCallList mCallList; 55 56 private Handler mTextDisplayHandler = new Handler(Looper.getMainLooper()) { 57 @Override 58 public void handleMessage(Message msg) { 59 String text; 60 switch (msg.what) { 61 case UPDATE_RECEIVED_TEXT: 62 text = (String) msg.obj; 63 mReceivedText.append(text); 64 break; 65 case UPDATE_SENT_TEXT: 66 text = (String) msg.obj; 67 mSentText.append(text); 68 break; 69 case RECEIVED_MESSAGE_GAP: 70 mReceivedText.append("\n> "); 71 break; 72 case SENT_MESSAGE_GAP: 73 mSentText.append("\n> "); 74 mTypingBox.setText(""); 75 break; 76 default: 77 Log.w(LOG_TAG, "Invalid message %d", msg.what); 78 } 79 } 80 }; 81 82 private Thread mReceiveReader = new Thread() { 83 @Override 84 public void run() { 85 // outer loop 86 while (true) { 87 begin : 88 // sleep and wait if there are no calls 89 while (mCallList.size() > 0) { 90 Call.RttCall rttCall = mCallList.getCall(0).getRttCall(); 91 if (rttCall == null) { 92 break; 93 } 94 // inner read loop 95 while (true) { 96 String receivedText; 97 receivedText = rttCall.read(); 98 if (receivedText == null) { 99 if (Thread.currentThread().isInterrupted()) { 100 break begin; 101 } 102 break; 103 } 104 Log.d(LOG_TAG, "Received %s", receivedText); 105 mTextDisplayHandler.removeMessages(RECEIVED_MESSAGE_GAP); 106 mTextDisplayHandler.sendEmptyMessageDelayed(RECEIVED_MESSAGE_GAP, 107 NEWLINE_DELAY_MILLIS); 108 mTextDisplayHandler.obtainMessage(UPDATE_RECEIVED_TEXT, receivedText) 109 .sendToTarget(); 110 } 111 } 112 if (Thread.currentThread().isInterrupted()) { 113 break; 114 } 115 try { 116 Thread.sleep(5000); 117 } catch (InterruptedException e) { 118 break; 119 } 120 } 121 } 122 }; 123 124 @Override 125 protected void onCreate(Bundle savedInstanceState) { 126 super.onCreate(savedInstanceState); 127 128 setContentView(R.layout.rtt_incall_screen); 129 130 mReceivedText = (TextView) findViewById(R.id.received_messages_text); 131 mSentText = (TextView) findViewById(R.id.sent_messages_text); 132 mTypingBox = (EditText) findViewById(R.id.rtt_typing_box); 133 134 Button endRttButton = (Button) findViewById(R.id.end_rtt_button); 135 Spinner rttModeSelector = (Spinner) findViewById(R.id.rtt_mode_selection_spinner); 136 137 ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, 138 R.array.rtt_mode_array, android.R.layout.simple_spinner_item); 139 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 140 rttModeSelector.setAdapter(adapter); 141 142 mCallList = TestCallList.getInstance(); 143 mCallList.addListener(new TestCallList.Listener() { 144 @Override 145 public void onCallRemoved(Call call) { 146 if (mCallList.size() == 0) { 147 Log.i(LOG_TAG, "Ending the RTT UI"); 148 finish(); 149 } 150 } 151 152 @Override 153 public void onRttStopped(Call call) { 154 TestRttActivity.this.finish(); 155 } 156 }); 157 158 endRttButton.setOnClickListener((view) -> { 159 Call call = mCallList.getCall(0); 160 call.stopRtt(); 161 }); 162 163 rttModeSelector.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 164 @Override 165 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 166 CharSequence selection = (CharSequence) parent.getItemAtPosition(position); 167 Call.RttCall call = mCallList.getCall(0).getRttCall(); 168 switch (selection.toString()) { 169 case "Full": 170 call.setRttMode(Call.RttCall.RTT_MODE_FULL); 171 break; 172 case "HCO": 173 call.setRttMode(Call.RttCall.RTT_MODE_HCO); 174 break; 175 case "VCO": 176 call.setRttMode(Call.RttCall.RTT_MODE_VCO); 177 break; 178 default: 179 Log.w(LOG_TAG, "Bad name for rtt mode: %s", selection.toString()); 180 } 181 } 182 183 @Override 184 public void onNothingSelected(AdapterView<?> parent) { 185 } 186 }); 187 188 mTypingBox.addTextChangedListener(new TextWatcher() { 189 @Override 190 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 191 } 192 193 @Override 194 public void onTextChanged(CharSequence s, int start, int before, int count) { 195 if (count == 0 || count < before) { 196 // ignore deletions and clears 197 return; 198 } 199 // Only appending at the end is supported. 200 int numCharsInserted = count - before; 201 String toAppend = 202 s.subSequence(s.length() - numCharsInserted, s.length()).toString(); 203 204 if (toAppend.isEmpty()) { 205 return; 206 } 207 try { 208 mCallList.getCall(0).getRttCall().write(toAppend); 209 } catch (IOException e) { 210 Log.w(LOG_TAG, "Exception sending text %s: %s", toAppend, e); 211 } 212 mTextDisplayHandler.removeMessages(SENT_MESSAGE_GAP); 213 mTextDisplayHandler.sendEmptyMessageDelayed(SENT_MESSAGE_GAP, NEWLINE_DELAY_MILLIS); 214 mTextDisplayHandler.obtainMessage(UPDATE_SENT_TEXT, toAppend).sendToTarget(); 215 } 216 217 @Override 218 public void afterTextChanged(Editable s) { 219 } 220 }); 221 222 } 223 224 @Override 225 public void onStart() { 226 super.onStart(); 227 mReceiveReader.start(); 228 } 229 230 @Override 231 public void onStop() { 232 super.onStop(); 233 mReceiveReader.interrupt(); 234 } 235 236} 237