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