Add support for RTT calls (part 1)
Adds logic for handling RTT call initiation and communication with the
InCallService and the ConnectionService and includes changes to the
testapps that exercise this functionality. This change handles RTT
initiation from the beginning of a call.
Change-Id: I3d713b662a100b2e0ad817b92005f044bcc60c62
Test: manual, through testapps
diff --git a/testapps/AndroidManifest.xml b/testapps/AndroidManifest.xml
index 03c1d60..a6a0d76 100644
--- a/testapps/AndroidManifest.xml
+++ b/testapps/AndroidManifest.xml
@@ -81,6 +81,16 @@
</intent-filter>
</activity>
+ <activity android:name="com.android.server.telecom.testapps.TestRttActivity"
+ android:process="com.android.server.telecom.testapps.TestInCallService"
+ android:label="@string/rttUiLabel"
+ android:launchMode="singleInstance">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
<activity android:name="com.android.server.telecom.testapps.TestCallActivity"
android:theme="@android:style/Theme.NoDisplay"
android:label="@string/testCallActivityLabel">
@@ -105,6 +115,11 @@
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="int" />
</intent-filter>
+ <intent-filter>
+ <action android:name="android.telecom.testapps.ACTION_RTT_CALL" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="tel" />
+ </intent-filter>
</activity>
<receiver android:name="com.android.server.telecom.testapps.CallNotificationReceiver"
diff --git a/testapps/res/layout/incall_screen.xml b/testapps/res/layout/incall_screen.xml
index 6a891e7..3ca8781 100644
--- a/testapps/res/layout/incall_screen.xml
+++ b/testapps/res/layout/incall_screen.xml
@@ -44,7 +44,16 @@
android:id="@+id/hold_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/holdButton" >
- </Button>
+ android:text="@string/holdButton"/>
+ <Button
+ android:id="@+id/rtt_iface_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/rttIfaceButton"/>
+ <Button
+ android:id="@+id/answer_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/answerCallButton"/>
</LinearLayout>
</LinearLayout>
diff --git a/testapps/res/layout/rtt_incall_screen.xml b/testapps/res/layout/rtt_incall_screen.xml
new file mode 100644
index 0000000..e7cbac4
--- /dev/null
+++ b/testapps/res/layout/rtt_incall_screen.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:id="@+id/received_messages_text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="> "
+ android:lines="7" />
+ <TextView
+ android:id="@+id/sent_messages_text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="> "
+ android:lines="7" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <Button
+ android:id="@+id/end_rtt_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/endRttButton" />
+ <Spinner
+ android:id="@+id/rtt_mode_selection_spinner"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ </LinearLayout>
+
+ <EditText
+ android:id="@+id/rtt_typing_box"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:lines="1"
+ android:hint="Type here" />
+</LinearLayout>
\ No newline at end of file
diff --git a/testapps/res/layout/testdialer_main.xml b/testapps/res/layout/testdialer_main.xml
index 2c3e5e4..e6c56b7 100644
--- a/testapps/res/layout/testdialer_main.xml
+++ b/testapps/res/layout/testdialer_main.xml
@@ -44,4 +44,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cancelMissedButton" />
+ <CheckBox
+ android:id="@+id/call_with_rtt_checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/startCallWithRtt"/>
</LinearLayout>
diff --git a/testapps/res/values/donottranslate_strings.xml b/testapps/res/values/donottranslate_strings.xml
index b9c2aa0..56cb476 100644
--- a/testapps/res/values/donottranslate_strings.xml
+++ b/testapps/res/values/donottranslate_strings.xml
@@ -40,6 +40,14 @@
<string name="endCallButton">End Call</string>
+ <string name="answerCallButton">Answer</string>
+
+ <string name="startCallWithRtt">Start call with RTT</string>
+
+ <string name="rttIfaceButton">RTT</string>
+
+ <string name="endRttButton">End RTT</string>
+
<string name="muteButton">Mute</string>
<string name="holdButton">Hold</string>
@@ -58,4 +66,22 @@
<string name="incomingCallNotPermitted">Incoming call not permitted.</string>
<string name="incomingCallNotPermittedCS">Incoming call not permitted (CS Reported).</string>
+
+ <string name="rttUiLabel">Test RTT UI</string>
+
+ <string-array name="rtt_mode_array">
+ <item>Full</item>
+ <item>HCO</item>
+ <item>VCO</item>
+ </string-array>
+
+ <string-array name="rtt_reply_one_liners">
+ <item>To RTT or not to RTT, that is the question...</item>
+ <item>Making TTY great again!</item>
+ <item>I would be more comfortable with real "Thyme" chatting. I don\'t know how to end
+ this pun</item>
+ <item>お疲れ様でした</item>
+ <item>The FCC has mandated that I respond... I will do so begrudgingly</item>
+ <item>😂😂😂💯</item>
+ </string-array>
</resources>
diff --git a/testapps/src/com/android/server/telecom/testapps/CallListAdapter.java b/testapps/src/com/android/server/telecom/testapps/CallListAdapter.java
index bea0e63..85785d5 100644
--- a/testapps/src/com/android/server/telecom/testapps/CallListAdapter.java
+++ b/testapps/src/com/android/server/telecom/testapps/CallListAdapter.java
@@ -103,7 +103,8 @@
state.setText(getStateString(call));
- Log.i(TAG, "Call found: " + handle.getSchemeSpecificPart() + ", " + durationMs);
+ Log.i(TAG, "Call found: " + ((handle == null) ? "null" : handle.getSchemeSpecificPart())
+ + ", " + durationMs);
return convertView;
}
diff --git a/testapps/src/com/android/server/telecom/testapps/CallNotificationReceiver.java b/testapps/src/com/android/server/telecom/testapps/CallNotificationReceiver.java
index aee5514..8fd2378 100644
--- a/testapps/src/com/android/server/telecom/testapps/CallNotificationReceiver.java
+++ b/testapps/src/com/android/server/telecom/testapps/CallNotificationReceiver.java
@@ -51,6 +51,8 @@
"com.android.server.telecom.testapps.ACTION_TWO_WAY_VIDEO_CALL";
static final String ACTION_AUDIO_CALL =
"com.android.server.telecom.testapps.ACTION_AUDIO_CALL";
+ static final String ACTION_RTT_CALL =
+ "com.android.server.telecom.testapps.ACTION_RTT_CALL";
/** {@inheritDoc} */
@Override
@@ -66,6 +68,8 @@
sendIncomingCallIntent(context, null, VideoProfile.STATE_RX_ENABLED);
} else if (ACTION_TWO_WAY_VIDEO_CALL.equals(action)) {
sendIncomingCallIntent(context, null, VideoProfile.STATE_BIDIRECTIONAL);
+ } else if (ACTION_RTT_CALL.equals(action)) {
+ sendIncomingRttCallIntent(context, null, VideoProfile.STATE_AUDIO_ONLY);
} else if (ACTION_AUDIO_CALL.equals(action)) {
sendIncomingCallIntent(context, null, VideoProfile.STATE_AUDIO_ONLY);
}
@@ -93,6 +97,23 @@
TelecomManager.from(context).addNewIncomingCall(phoneAccount, extras);
}
+ public static void sendIncomingRttCallIntent(Context context, Uri handle, int videoState) {
+ PhoneAccountHandle phoneAccount = new PhoneAccountHandle(
+ new ComponentName(context, TestConnectionService.class),
+ CallServiceNotifier.SIM_SUBSCRIPTION_ID);
+
+ // For the purposes of testing, indicate whether the incoming call is a video call by
+ // stashing an indicator in the EXTRA_INCOMING_CALL_EXTRAS.
+ Bundle extras = new Bundle();
+ extras.putInt(TestConnectionService.EXTRA_START_VIDEO_STATE, videoState);
+ if (handle != null) {
+ extras.putParcelable(TestConnectionService.EXTRA_HANDLE, handle);
+ }
+ extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, true);
+
+ TelecomManager.from(context).addNewIncomingCall(phoneAccount, extras);
+ }
+
public static void addNewUnknownCall(Context context, Uri handle, Bundle extras) {
Log.i(TAG, "Adding new unknown call with handle " + handle);
PhoneAccountHandle phoneAccount = new PhoneAccountHandle(
diff --git a/testapps/src/com/android/server/telecom/testapps/CallServiceNotifier.java b/testapps/src/com/android/server/telecom/testapps/CallServiceNotifier.java
index 9292273..ba58655 100644
--- a/testapps/src/com/android/server/telecom/testapps/CallServiceNotifier.java
+++ b/testapps/src/com/android/server/telecom/testapps/CallServiceNotifier.java
@@ -119,6 +119,7 @@
.setSubscriptionAddress(Uri.parse("tel:555-TEST"))
.setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
PhoneAccount.CAPABILITY_VIDEO_CALLING |
+ PhoneAccount.CAPABILITY_RTT |
PhoneAccount.CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE)
.setIcon(Icon.createWithResource(
context.getResources(), R.drawable.stat_sys_phone_call))
@@ -139,6 +140,7 @@
.setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
PhoneAccount.CAPABILITY_VIDEO_CALLING |
+ PhoneAccount.CAPABILITY_RTT |
PhoneAccount.CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE)
.setIcon(Icon.createWithResource(
context.getResources(), R.drawable.stat_sys_phone_call))
diff --git a/testapps/src/com/android/server/telecom/testapps/RttChatbot.java b/testapps/src/com/android/server/telecom/testapps/RttChatbot.java
new file mode 100644
index 0000000..3b16bd4
--- /dev/null
+++ b/testapps/src/com/android/server/telecom/testapps/RttChatbot.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.telecom.testapps;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.telecom.Connection;
+import android.telecom.Log;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.util.Random;
+
+public class RttChatbot {
+ private static final String LOG_TAG = RttChatbot.class.getSimpleName();
+ private static final long PER_CHARACTER_DELAY_MS = 100;
+ private static final long MSG_WAIT_DELAY_MS = 3999;
+ private static final double ONE_LINER_FREQUENCY = 0.1;
+ private static final String REPLY_PREFIX = "You said: ";
+
+ private static final int BEGIN_SEND_REPLY_MESSAGE = 1;
+ private static final int SEND_CHARACTER = 2;
+ private static final int APPEND_TO_INPUT_BUFFER = 3;
+
+ private final Connection.RttTextStream mRttTextStream;
+ private final Random mRandom = new Random();
+ private final String[] mOneLiners;
+ private Handler mHandler;
+
+ private final class ReplyHandler extends Handler {
+ private StringBuilder mInputSoFar;
+
+ public ReplyHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case BEGIN_SEND_REPLY_MESSAGE:
+ removeMessages(SEND_CHARACTER);
+ sendReplyMessage();
+ break;
+ case SEND_CHARACTER:
+ try {
+ mRttTextStream.write((String) msg.obj);
+ } catch (IOException e) {
+ }
+ break;
+ case APPEND_TO_INPUT_BUFFER:
+ removeMessages(BEGIN_SEND_REPLY_MESSAGE);
+ sendEmptyMessageDelayed(BEGIN_SEND_REPLY_MESSAGE, MSG_WAIT_DELAY_MS);
+ String toAppend = (String) msg.obj;
+ if (mInputSoFar == null) {
+ mInputSoFar = new StringBuilder(toAppend);
+ } else {
+ mInputSoFar.append(toAppend);
+ }
+ Log.d(LOG_TAG, "Got %s to append, total text now %s",
+ toAppend, mInputSoFar.toString());
+ break;
+ }
+ }
+
+ private void sendReplyMessage() {
+ String messageToSend;
+ if (mRandom.nextDouble() < ONE_LINER_FREQUENCY) {
+ messageToSend = mOneLiners[mRandom.nextInt(mOneLiners.length)];
+ } else {
+ messageToSend = REPLY_PREFIX + mInputSoFar.toString();
+ }
+ mInputSoFar = null;
+ Log.i(LOG_TAG, "Begin send reply message: %s", messageToSend);
+ int[] charsToSend = messageToSend.codePoints().toArray();
+ for (int i = 0; i < charsToSend.length; i++) {
+ Message msg = obtainMessage(SEND_CHARACTER,
+ new String(new int[] {charsToSend[i]}, 0, 1));
+ sendMessageDelayed(msg, PER_CHARACTER_DELAY_MS * i);
+ }
+ }
+ }
+
+ public RttChatbot(Context context, Connection.RttTextStream textStream) {
+ mOneLiners = context.getResources().getStringArray(R.array.rtt_reply_one_liners);
+ mRttTextStream = textStream;
+ }
+
+ public void start() {
+ Log.i(LOG_TAG, "Starting RTT chatbot.");
+ HandlerThread ht = new HandlerThread("RttChatbotSender");
+ ht.start();
+ mHandler = new ReplyHandler(ht.getLooper());
+ Thread receiveThread = new Thread(() -> {
+ while (true) {
+ String charsReceived = mRttTextStream.read();
+ if (charsReceived == null) {
+ if (Thread.currentThread().isInterrupted()) {
+ Log.w(LOG_TAG, "Thread interrupted");
+ break;
+ }
+ Log.w(LOG_TAG, "Stream closed");
+ break;
+ }
+ if (charsReceived.length() == 0) {
+ continue;
+ }
+ mHandler.obtainMessage(APPEND_TO_INPUT_BUFFER, charsReceived)
+ .sendToTarget();
+ }
+ }, "RttChatbotReceiver");
+ receiveThread.start();
+ }
+}
diff --git a/testapps/src/com/android/server/telecom/testapps/TestCallActivity.java b/testapps/src/com/android/server/telecom/testapps/TestCallActivity.java
index 862ccf7..76f2058 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestCallActivity.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestCallActivity.java
@@ -52,6 +52,9 @@
public static final String ACTION_SEND_UPGRADE_REQUEST =
"android.telecom.testapps.ACTION_SEND_UPGRADE_REQUEST";
+ static final String ACTION_RTT_CALL =
+ "android.telecom.testapps.ACTION_RTT_CALL";
+
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -65,6 +68,9 @@
CallNotificationReceiver.addNewUnknownCall(this, data, intent.getExtras());
} else if (ACTION_HANGUP_CALLS.equals(action)) {
CallNotificationReceiver.hangupCalls(this);
+ } else if (ACTION_RTT_CALL.equals(action)) {
+ CallNotificationReceiver.sendIncomingRttCallIntent(
+ this, data, VideoProfile.STATE_AUDIO_ONLY);
} else if (ACTION_SEND_UPGRADE_REQUEST.equals(action)) {
CallNotificationReceiver.sendUpgradeRequest(this, data);
} else {
diff --git a/testapps/src/com/android/server/telecom/testapps/TestCallList.java b/testapps/src/com/android/server/telecom/testapps/TestCallList.java
index 391a588..4419b17 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestCallList.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestCallList.java
@@ -32,7 +32,7 @@
/**
* Maintains a list of calls received via the {@link TestInCallServiceImpl}.
*/
-public class TestCallList extends Call.Listener {
+public class TestCallList extends Call.Callback {
public static abstract class Listener {
public void onCallAdded(Call call) {}
@@ -126,7 +126,7 @@
}
Log.i(TAG, "addCall: " + call + " " + System.identityHashCode(this));
mCalls.add(call);
- call.addListener(this);
+ call.registerCallback(this);
for (Listener l : mListeners) {
l.onCallAdded(call);
@@ -140,7 +140,7 @@
}
Log.i(TAG, "removeCall: " + call);
mCalls.remove(call);
- call.removeListener(this);
+ call.unregisterCallback(this);
for (Listener l : mListeners) {
l.onCallRemoved(call);
@@ -214,4 +214,15 @@
}
}
}
+
+ @Override
+ public void onRttStatusChanged(Call call, boolean enabled, Call.RttCall rttCall) {
+ Log.v(TAG, "onRttStatusChanged: call = " + call + " " + System.identityHashCode(this));
+
+ if (call != null) {
+ // Did you have another call? Well too bad, this class isn't gonna handle it.
+ mCalls.clear();
+ mCalls.add(call);
+ }
+ }
}
diff --git a/testapps/src/com/android/server/telecom/testapps/TestConnectionManager.java b/testapps/src/com/android/server/telecom/testapps/TestConnectionManager.java
index 5b0cf63..c2d8852 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestConnectionManager.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestConnectionManager.java
@@ -135,6 +135,7 @@
mRemote.registerCallback(mRemoteCallback);
setState(mRemote.getState());
setVideoState(mRemote.getVideoState());
+ setConnectionProperties(remote.getConnectionProperties());
}
@Override
diff --git a/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java b/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
index 0150dbe..6c07073 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
@@ -25,6 +25,7 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
+import android.os.ParcelFileDescriptor;
import android.support.v4.content.LocalBroadcastManager;
import android.telecom.Conference;
import android.telecom.Connection;
@@ -35,7 +36,7 @@
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
-import android.util.Log;
+import android.telecom.Log;
import android.widget.Toast;
import com.android.server.telecom.testapps.R;
@@ -57,6 +58,7 @@
public static final String EXTRA_HANDLE = "extra_handle";
+ private static final String LOG_TAG = TestConnectionService.class.getSimpleName();
/**
* Random number generator used to generate phone numbers.
*/
@@ -271,6 +273,8 @@
/** Used to play an audio tone during a call. */
private MediaPlayer mMediaPlayer;
+ // Used to provide text reply in an RTT call
+ private RttChatbot mRttChatbot;
@Override
public boolean onUnbind(Intent intent) {
@@ -309,11 +313,22 @@
Toast.LENGTH_SHORT).show();
}
+ if (originalRequest.isRequestingRtt()) {
+ Log.i(LOG_TAG, "Is RTT call. Starting chatbot service.");
+ mRttChatbot = new RttChatbot(getApplicationContext(),
+ originalRequest.getRttTextStream());
+ mRttChatbot.start();
+ }
+
log("gateway package [" + gatewayPackage + "], original handle [" +
originalHandle + "]");
final TestConnection connection = new TestConnection(false /* isIncoming */);
setAddress(connection, handle);
+ if (originalRequest.isRequestingRtt()) {
+ connection.setConnectionProperties(
+ connection.getConnectionProperties() | Connection.PROPERTY_IS_RTT);
+ }
// If the number starts with 555, then we handle it ourselves. If not, then we
// use a remote connection service.
@@ -377,6 +392,13 @@
connectionExtras.putString(Connection.EXTRA_CALL_SUBJECT,
"This is a test of call subject lines.");
}
+
+ if (request.isRequestingRtt()) {
+ Log.i(LOG_TAG, "Is RTT call. Starting chatbot service.");
+ mRttChatbot = new RttChatbot(getApplicationContext(), request.getRttTextStream());
+ mRttChatbot.start();
+ }
+
connection.putExtras(connectionExtras);
setAddress(connection, address);
@@ -385,11 +407,6 @@
addCall(connection);
- ConnectionRequest newRequest = new ConnectionRequest(
- request.getAccountHandle(),
- address,
- request.getExtras(),
- videoState);
connection.setVideoState(videoState);
return connection;
} else {
diff --git a/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java b/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java
index 596d18d..c7eccf7 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java
@@ -12,15 +12,15 @@
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
+import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;
-import com.android.server.telecom.testapps.R;
-
public class TestDialerActivity extends Activity {
private static final int REQUEST_CODE_SET_DEFAULT_DIALER = 1;
private EditText mNumberView;
+ private CheckBox mRttCheckbox;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -55,7 +55,8 @@
});
mNumberView = (EditText) findViewById(R.id.number);
- updateEditTextWithNumber();
+ mRttCheckbox = (CheckBox) findViewById(R.id.call_with_rtt_checkbox);
+ updateMutableUi();
}
@Override
@@ -72,13 +73,15 @@
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
- updateEditTextWithNumber();
+ updateMutableUi();
}
- private void updateEditTextWithNumber() {
+ private void updateMutableUi() {
Intent intent = getIntent();
if (intent != null) {
mNumberView.setText(intent.getDataString());
+ mRttCheckbox.setChecked(
+ intent.getBooleanExtra(TelecomManager.EXTRA_START_CALL_WITH_RTT, false));
}
}
@@ -127,7 +130,10 @@
private Bundle createCallIntentExtras() {
Bundle extras = new Bundle();
- extras.putString("com.android.server.telecom.testapps.CALL_EXTRAS", "Yorke was here");
+ extras.putString("com.android.server.telecom.testapps.CALL_EXTRAS", "Hall was here");
+ if (mRttCheckbox.isChecked()) {
+ extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, true);
+ }
Bundle intentExtras = new Bundle();
intentExtras.putBundle(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras);
diff --git a/testapps/src/com/android/server/telecom/testapps/TestInCallUI.java b/testapps/src/com/android/server/telecom/testapps/TestInCallUI.java
index ce53709..809036c 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestInCallUI.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestInCallUI.java
@@ -17,9 +17,10 @@
package com.android.server.telecom.testapps;
import android.app.Activity;
-import android.graphics.Color;
+import android.content.Intent;
import android.os.Bundle;
import android.telecom.Call;
+import android.telecom.VideoProfile;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
@@ -46,7 +47,7 @@
@Override
public void onCallRemoved(Call call) {
if (mCallList.size() == 0) {
- Log.i("Santos", "Ending the incall UI");
+ Log.i(TestInCallUI.class.getSimpleName(), "Ending the incall UI");
finish();
}
}
@@ -55,6 +56,8 @@
View endCallButton = findViewById(R.id.end_call_button);
View holdButton = findViewById(R.id.hold_button);
View muteButton = findViewById(R.id.mute_button);
+ View rttIfaceButton = findViewById(R.id.rtt_iface_button);
+ View answerButton = findViewById(R.id.answer_button);
endCallButton.setOnClickListener(new OnClickListener() {
@Override
@@ -83,9 +86,24 @@
public void onClick(View view) {
Call call = mCallList.getCall(0);
if (call != null) {
+
}
}
});
+ rttIfaceButton.setOnClickListener((view) -> {
+ Call call = mCallList.getCall(0);
+ if (call.isRttActive()) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setClass(this, TestRttActivity.class);
+ startActivity(intent);
+ }
+ });
+ answerButton.setOnClickListener(view -> {
+ Call call = mCallList.getCall(0);
+ if (call.getState() == Call.STATE_RINGING) {
+ call.answer(VideoProfile.STATE_AUDIO_ONLY);
+ }
+ });
}
/** ${inheritDoc} */
diff --git a/testapps/src/com/android/server/telecom/testapps/TestRttActivity.java b/testapps/src/com/android/server/telecom/testapps/TestRttActivity.java
new file mode 100644
index 0000000..ce962b4
--- /dev/null
+++ b/testapps/src/com/android/server/telecom/testapps/TestRttActivity.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.telecom.testapps;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.telecom.Call;
+import android.telecom.Log;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+
+public class TestRttActivity extends Activity {
+ private static final String LOG_TAG = TestRttActivity.class.getSimpleName();
+ private static final long NEWLINE_DELAY_MILLIS = 3000;
+
+ private static final int UPDATE_RECEIVED_TEXT = 1;
+ private static final int UPDATE_SENT_TEXT = 2;
+ private static final int RECEIVED_MESSAGE_GAP = 3;
+ private static final int SENT_MESSAGE_GAP = 4;
+
+ private TextView mReceivedText;
+ private TextView mSentText;
+ private EditText mTypingBox;
+
+ private TestCallList mCallList;
+
+ private Handler mTextDisplayHandler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ String text;
+ switch (msg.what) {
+ case UPDATE_RECEIVED_TEXT:
+ text = (String) msg.obj;
+ mReceivedText.append(text);
+ break;
+ case UPDATE_SENT_TEXT:
+ text = (String) msg.obj;
+ mSentText.append(text);
+ break;
+ case RECEIVED_MESSAGE_GAP:
+ mReceivedText.append("\n> ");
+ break;
+ case SENT_MESSAGE_GAP:
+ mSentText.append("\n> ");
+ mTypingBox.setText("");
+ break;
+ default:
+ Log.w(LOG_TAG, "Invalid message %d", msg.what);
+ }
+ }
+ };
+
+ private Thread mReceiveReader = new Thread() {
+ @Override
+ public void run() {
+ // outer loop
+ while (true) {
+ begin :
+ // sleep and wait if there are no calls
+ while (mCallList.size() > 0) {
+ Call.RttCall rttCall = mCallList.getCall(0).getRttCall();
+ if (rttCall == null) {
+ break;
+ }
+ // inner read loop
+ while (true) {
+ String receivedText = rttCall.read();
+ if (receivedText == null) {
+ if (Thread.currentThread().isInterrupted()) {
+ break begin;
+ }
+ break;
+ }
+ Log.d(LOG_TAG, "Received %s", receivedText);
+ mTextDisplayHandler.removeMessages(RECEIVED_MESSAGE_GAP);
+ mTextDisplayHandler.sendEmptyMessageDelayed(RECEIVED_MESSAGE_GAP,
+ NEWLINE_DELAY_MILLIS);
+ mTextDisplayHandler.obtainMessage(UPDATE_RECEIVED_TEXT, receivedText)
+ .sendToTarget();
+ }
+ }
+ if (Thread.currentThread().isInterrupted()) {
+ break;
+ }
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException e) {
+ break;
+ }
+ }
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.rtt_incall_screen);
+
+ mReceivedText = (TextView) findViewById(R.id.received_messages_text);
+ mSentText = (TextView) findViewById(R.id.sent_messages_text);
+ mTypingBox = (EditText) findViewById(R.id.rtt_typing_box);
+
+ Button endRttButton = (Button) findViewById(R.id.end_rtt_button);
+ Spinner rttModeSelector = (Spinner) findViewById(R.id.rtt_mode_selection_spinner);
+
+ ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
+ R.array.rtt_mode_array, android.R.layout.simple_spinner_item);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ rttModeSelector.setAdapter(adapter);
+
+ mCallList = TestCallList.getInstance();
+ mCallList.addListener(new TestCallList.Listener() {
+ @Override
+ public void onCallRemoved(Call call) {
+ if (mCallList.size() == 0) {
+ Log.i(LOG_TAG, "Ending the RTT UI");
+ finish();
+ }
+ }
+ });
+
+ endRttButton.setOnClickListener((view) -> {
+ Call call = mCallList.getCall(0);
+ call.stopRtt();
+ });
+
+ rttModeSelector.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ CharSequence selection = (CharSequence) parent.getItemAtPosition(position);
+ Call.RttCall call = mCallList.getCall(0).getRttCall();
+ switch (selection.toString()) {
+ case "Full":
+ call.setRttMode(Call.RttCall.RTT_MODE_FULL);
+ break;
+ case "HCO":
+ call.setRttMode(Call.RttCall.RTT_MODE_HCO);
+ break;
+ case "VCO":
+ call.setRttMode(Call.RttCall.RTT_MODE_VCO);
+ break;
+ default:
+ Log.w(LOG_TAG, "Bad name for rtt mode: %s", selection.toString());
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+
+ mTypingBox.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ if (count == 0 || count < before) {
+ // ignore deletions and clears
+ return;
+ }
+ // Only appending at the end is supported.
+ int numCharsInserted = count - before;
+ String toAppend =
+ s.subSequence(s.length() - numCharsInserted, s.length()).toString();
+
+ if (toAppend.isEmpty()) {
+ return;
+ }
+ try {
+ mCallList.getCall(0).getRttCall().write(toAppend);
+ } catch (IOException e) {
+ Log.w(LOG_TAG, "Exception sending text %s: %s", toAppend, e);
+ }
+ mTextDisplayHandler.removeMessages(SENT_MESSAGE_GAP);
+ mTextDisplayHandler.sendEmptyMessageDelayed(SENT_MESSAGE_GAP, NEWLINE_DELAY_MILLIS);
+ mTextDisplayHandler.obtainMessage(UPDATE_SENT_TEXT, toAppend).sendToTarget();
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ }
+ });
+
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ mReceiveReader.start();
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ mReceiveReader.interrupt();
+ }
+
+}