Implement mid-call RTT initiation and teardown
Adds functionality to testapps and to framework to allow for local and
remote initiation and disconnection of RTT.
Test: manual
Change-Id: I0e8248b495a7d3750c840591f1fa5388b34a32e2
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index d84bc2b..2e79478 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -35,7 +35,6 @@
import android.telecom.Log;
import android.telecom.Logging.EventManager;
import android.telecom.ParcelableConnection;
-import android.telecom.ParcelableRttCall;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.Response;
@@ -87,6 +86,8 @@
private static final int RTT_PIPE_READ_SIDE_INDEX = 0;
private static final int RTT_PIPE_WRITE_SIDE_INDEX = 1;
+
+ private static final int INVALID_RTT_REQUEST_ID = -1;
/**
* Listener for events on the call.
*/
@@ -123,6 +124,8 @@
void onHoldToneRequested(Call call);
void onConnectionEvent(Call call, String event, Bundle extras);
void onExternalCallChanged(Call call, boolean isExternalCall);
+ void onRttInitiationFailure(Call call, int reason);
+ void onRemoteRttRequest(Call call, int requestId);
}
public abstract static class ListenerBase implements Listener {
@@ -184,13 +187,16 @@
public boolean onCanceledViaNewOutgoingCallBroadcast(Call call, long disconnectionTimeout) {
return false;
}
-
@Override
public void onHoldToneRequested(Call call) {}
@Override
public void onConnectionEvent(Call call, String event, Bundle extras) {}
@Override
public void onExternalCallChanged(Call call, boolean isExternalCall) {}
+ @Override
+ public void onRttInitiationFailure(Call call, int reason) {}
+ @Override
+ public void onRemoteRttRequest(Call call, int requestId) {}
}
private final CallerInfoLookupHelper.OnQueryCompleteListener mCallerInfoQueryListener =
@@ -426,6 +432,11 @@
private int mRttMode;
/**
+ * Integer indicating the remote RTT request ID that is pending a response from the user.
+ */
+ private int mPendingRttRequestId = INVALID_RTT_REQUEST_ID;
+
+ /**
* Persists the specified parameters and initializes the new instance.
*
* @param context The context.
@@ -1127,7 +1138,7 @@
if (changedProperties != 0) {
int previousProperties = mConnectionProperties;
mConnectionProperties = connectionProperties;
- setIsRttCall((mConnectionProperties & Connection.PROPERTY_IS_RTT) ==
+ setRttStreams((mConnectionProperties & Connection.PROPERTY_IS_RTT) ==
Connection.PROPERTY_IS_RTT);
boolean didRttChange =
(changedProperties & Connection.PROPERTY_IS_RTT) == Connection.PROPERTY_IS_RTT;
@@ -2043,7 +2054,22 @@
return mSpeakerphoneOn;
}
- public void setIsRttCall(boolean shouldBeRtt) {
+ public void stopRtt() {
+ if (mConnectionService != null) {
+ mConnectionService.stopRtt(this);
+ } else {
+ // If this gets called by the in-call app before the connection service is set, we'll
+ // just ignore it since it's really not supposed to happen.
+ Log.w(this, "stopRtt() called before connection service is set.");
+ }
+ }
+
+ public void sendRttRequest() {
+ setRttStreams(true);
+ mConnectionService.startRtt(this, getInCallToCsRttPipeForCs(), getCsToInCallRttPipeForCs());
+ }
+
+ public void setRttStreams(boolean shouldBeRtt) {
boolean areStreamsInitialized = mInCallToConnectionServiceStreams != null
&& mConnectionServiceToInCallStreams != null;
if (shouldBeRtt && !areStreamsInitialized) {
@@ -2060,6 +2086,45 @@
}
}
+ public void onRttConnectionFailure(int reason) {
+ setRttStreams(false);
+ for (Listener l : mListeners) {
+ l.onRttInitiationFailure(this, reason);
+ }
+ }
+
+ public void onRemoteRttRequest() {
+ if (isRttCall()) {
+ Log.w(this, "Remote RTT request on a call that's already RTT");
+ return;
+ }
+
+ mPendingRttRequestId = mCallsManager.getNextRttRequestId();
+ for (Listener l : mListeners) {
+ l.onRemoteRttRequest(this, mPendingRttRequestId);
+ }
+ }
+
+ public void handleRttRequestResponse(int id, boolean accept) {
+ if (mPendingRttRequestId == INVALID_RTT_REQUEST_ID) {
+ Log.w(this, "Response received to a nonexistent RTT request: %d", id);
+ return;
+ }
+ if (id != mPendingRttRequestId) {
+ Log.w(this, "Response ID %d does not match expected %d", id, mPendingRttRequestId);
+ return;
+ }
+ setRttStreams(accept);
+ if (accept) {
+ Log.i(this, "RTT request %d accepted.", id);
+ mConnectionService.respondToRttRequest(
+ this, getInCallToCsRttPipeForCs(), getCsToInCallRttPipeForCs());
+ } else {
+ Log.i(this, "RTT request %d rejected.", id);
+ mConnectionService.respondToRttRequest(this, null, null);
+ }
+ }
+
public void closeRttPipes() {
// TODO: may defer this until call is removed?
}
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 8d393e8..69d9616 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -51,7 +51,6 @@
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
-import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.AsyncEmergencyContactNotifier;
@@ -69,7 +68,6 @@
import com.android.server.telecom.components.ErrorDialogActivity;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -177,6 +175,7 @@
*/
private int mCallId = 0;
+ private int mRttRequestId = 0;
/**
* Stores the current foreground user.
*/
@@ -767,7 +766,7 @@
if (extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) {
if (phoneAccount != null &&
phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) {
- call.setIsRttCall(true);
+ call.setRttStreams(true);
}
}
@@ -1012,7 +1011,7 @@
&& extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) {
if (accountToUse != null
&& accountToUse.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) {
- call.setIsRttCall(true);
+ call.setRttStreams(true);
}
}
}
@@ -1465,7 +1464,7 @@
mPhoneAccountRegistrar.getPhoneAccountUnchecked(account);
if (realPhoneAccount != null
&& realPhoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) {
- call.setIsRttCall(true);
+ call.setRttStreams(true);
}
}
@@ -2306,6 +2305,12 @@
}
}
+ public int getNextRttRequestId() {
+ synchronized (mLock) {
+ return (++mRttRequestId);
+ }
+ }
+
/**
* Callback when foreground user is switched. We will reload missed call in all profiles
* including the user itself. There may be chances that profiles are not started yet.
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index 1d44a1d..cb6ff93 100644
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -23,6 +23,7 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.UserHandle;
import android.telecom.CallAudioState;
@@ -771,6 +772,54 @@
Log.endSession();
}
}
+
+ @Override
+ public void onRttInitiationSuccess(String callId, Session.Info sessionInfo)
+ throws RemoteException {
+
+ }
+
+ @Override
+ public void onRttInitiationFailure(String callId, int reason, Session.Info sessionInfo)
+ throws RemoteException {
+ Log.startSession(sessionInfo, "CSW.oRIF");
+ long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ Call call = mCallIdMapper.getCall(callId);
+ if (call != null) {
+ call.onRttConnectionFailure(reason);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ Log.endSession();
+ }
+ }
+
+ @Override
+ public void onRttSessionRemotelyTerminated(String callId, Session.Info sessionInfo)
+ throws RemoteException {
+
+ }
+
+ @Override
+ public void onRemoteRttRequest(String callId, Session.Info sessionInfo)
+ throws RemoteException {
+ Log.startSession(sessionInfo, "CSW.oRRR");
+ long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ Call call = mCallIdMapper.getCall(callId);
+ if (call != null) {
+ call.onRemoteRttRequest();
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ Log.endSession();
+ }
+ }
}
private final Adapter mAdapter = new Adapter();
@@ -870,7 +919,8 @@
mCallsManager.getEmergencyCallHelper().getLastEmergencyCallTimeMillis());
}
- Log.addEvent(call, LogUtils.Events.START_CONNECTION, Log.piiHandle(call.getHandle()));
+ Log.addEvent(call, LogUtils.Events.START_CONNECTION,
+ Log.piiHandle(call.getHandle()));
// For self-managed incoming calls, if there is another ongoing call Telecom is
// responsible for showing a UI to ask the user if they'd like to answer this
@@ -1222,6 +1272,41 @@
}
}
+ void startRtt(Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall) {
+ final String callId = mCallIdMapper.getCallId(call);
+ if (callId != null && isServiceValid("startRtt")) {
+ try {
+ logOutgoing("startRtt: %s %s %s", callId, fromInCall, toInCall);
+ mServiceInterface.startRtt(callId, fromInCall, toInCall, Log.getExternalSession());
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ void stopRtt(Call call) {
+ final String callId = mCallIdMapper.getCallId(call);
+ if (callId != null && isServiceValid("stopRtt")) {
+ try {
+ logOutgoing("stopRtt: %s", callId);
+ mServiceInterface.stopRtt(callId, Log.getExternalSession());
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ void respondToRttRequest(
+ Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall) {
+ final String callId = mCallIdMapper.getCallId(call);
+ if (callId != null && isServiceValid("respondToRttRequest")) {
+ try {
+ logOutgoing("respondToRttRequest: %s %s %s", callId, fromInCall, toInCall);
+ mServiceInterface.respondToRttUpgradeRequest(
+ callId, fromInCall, toInCall, Log.getExternalSession());
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
/** {@inheritDoc} */
@Override
protected void setServiceInterface(IBinder binder) {
diff --git a/src/com/android/server/telecom/InCallAdapter.java b/src/com/android/server/telecom/InCallAdapter.java
index 4b54760..0eeec44 100644
--- a/src/com/android/server/telecom/InCallAdapter.java
+++ b/src/com/android/server/telecom/InCallAdapter.java
@@ -496,13 +496,18 @@
}
@Override
- public void sendRttRequest() {
+ public void sendRttRequest(String callId) {
try {
Log.startSession("ICA.sRR");
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- // TODO
+ Call call = mCallIdMapper.getCall(callId);
+ if (call != null) {
+ call.sendRttRequest();
+ } else {
+ Log.w(this, "stopRtt(): call %s not found", callId);
+ }
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -513,13 +518,18 @@
}
@Override
- public void respondToRttRequest(int id, boolean accept) {
+ public void respondToRttRequest(String callId, int id, boolean accept) {
try {
Log.startSession("ICA.rTRR");
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- // TODO
+ Call call = mCallIdMapper.getCall(callId);
+ if (call != null) {
+ call.handleRttRequestResponse(id, accept);
+ } else {
+ Log.w(this, "respondToRttRequest(): call %s not found", callId);
+ }
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -530,13 +540,18 @@
}
@Override
- public void stopRtt() {
+ public void stopRtt(String callId) {
try {
Log.startSession("ICA.sRTT");
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- // TODO
+ Call call = mCallIdMapper.getCall(callId);
+ if (call != null) {
+ call.stopRtt();
+ } else {
+ Log.w(this, "stopRtt(): call %s not found", callId);
+ }
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -547,7 +562,7 @@
}
@Override
- public void setRttMode(int mode) {
+ public void setRttMode(String callId, int mode) {
try {
Log.startSession("ICA.sRM");
long token = Binder.clearCallingIdentity();
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 0d2e30c..cbff31e 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -29,7 +29,6 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
-import android.os.Parcel;
import android.os.RemoteException;
import android.os.Trace;
import android.os.UserHandle;
@@ -612,6 +611,17 @@
public void onConnectionEvent(Call call, String event, Bundle extras) {
notifyConnectionEvent(call, event, extras);
}
+
+ @Override
+ public void onRttInitiationFailure(Call call, int reason) {
+ notifyRttInitiationFailure(call, reason);
+ updateCall(call, false, true);
+ }
+
+ @Override
+ public void onRemoteRttRequest(Call call, int requestId) {
+ notifyRemoteRttRequest(call, requestId);
+ }
};
private final SystemStateListener mSystemStateListener = new SystemStateListener() {
@@ -925,6 +935,37 @@
}
}
+ private void notifyRttInitiationFailure(Call call, int reason) {
+ if (!mInCallServices.isEmpty()) {
+ mInCallServices.entrySet().stream()
+ .filter((entry) -> entry.getKey().equals(mInCallServiceConnection.getInfo()))
+ .forEach((entry) -> {
+ try {
+ Log.i(this, "notifyRttFailure, call %s, incall %s",
+ call, entry.getKey());
+ entry.getValue().onRttInitiationFailure(mCallIdMapper.getCallId(call),
+ reason);
+ } catch (RemoteException ignored) {
+ }
+ });
+ }
+ }
+
+ private void notifyRemoteRttRequest(Call call, int requestId) {
+ if (!mInCallServices.isEmpty()) {
+ mInCallServices.entrySet().stream()
+ .filter((entry) -> entry.getKey().equals(mInCallServiceConnection.getInfo()))
+ .forEach((entry) -> {
+ try {
+ Log.i(this, "notifyRemoteRttRequest, call %s, incall %s",
+ call, entry.getKey());
+ entry.getValue().onRttUpgradeRequest(
+ mCallIdMapper.getCallId(call), requestId);
+ } catch (RemoteException ignored) {
+ }
+ });
+ }
+ }
/**
* Unbinds an existing bound connection to the in-call app.
*/
diff --git a/testapps/AndroidManifest.xml b/testapps/AndroidManifest.xml
index 2cdfc55..26735a6 100644
--- a/testapps/AndroidManifest.xml
+++ b/testapps/AndroidManifest.xml
@@ -120,6 +120,10 @@
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="tel" />
</intent-filter>
+ <intent-filter>
+ <action android:name="android.telecom.testapps.ACTION_REMOTE_RTT_UPGRADE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </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 3ca8781..502bdf4 100644
--- a/testapps/res/layout/incall_screen.xml
+++ b/testapps/res/layout/incall_screen.xml
@@ -26,7 +26,8 @@
android:divider="#FFCC00"
android:dividerHeight="4px">
</ListView>
- <LinearLayout
+ <GridLayout
+ android:columnCount="4"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
@@ -55,5 +56,15 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/answerCallButton"/>
- </LinearLayout>
+ <Button
+ android:id="@+id/start_rtt_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/startRttButton"/>
+ <Button
+ android:id="@+id/accept_rtt_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/acceptRttButton"/>
+ </GridLayout>
</LinearLayout>
diff --git a/testapps/res/values/donottranslate_strings.xml b/testapps/res/values/donottranslate_strings.xml
index f24625e..5a7e500 100644
--- a/testapps/res/values/donottranslate_strings.xml
+++ b/testapps/res/values/donottranslate_strings.xml
@@ -48,6 +48,10 @@
<string name="endRttButton">End RTT</string>
+ <string name="startRttButton">Start RTT</string>
+
+ <string name="acceptRttButton">Accept RTT request</string>
+
<string name="muteButton">Mute</string>
<string name="holdButton">Hold</string>
diff --git a/testapps/src/com/android/server/telecom/testapps/CallNotificationReceiver.java b/testapps/src/com/android/server/telecom/testapps/CallNotificationReceiver.java
index 8fd2378..2d43e76 100644
--- a/testapps/src/com/android/server/telecom/testapps/CallNotificationReceiver.java
+++ b/testapps/src/com/android/server/telecom/testapps/CallNotificationReceiver.java
@@ -144,4 +144,9 @@
intent.setData(data);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
}
+
+ public static void remoteRttUpgrade(Context context) {
+ final Intent intent = new Intent(TestCallActivity.ACTION_REMOTE_RTT_UPGRADE);
+ LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
+ }
}
diff --git a/testapps/src/com/android/server/telecom/testapps/RttChatbot.java b/testapps/src/com/android/server/telecom/testapps/RttChatbot.java
index 3b16bd4..44439ee 100644
--- a/testapps/src/com/android/server/telecom/testapps/RttChatbot.java
+++ b/testapps/src/com/android/server/telecom/testapps/RttChatbot.java
@@ -47,6 +47,8 @@
private final Random mRandom = new Random();
private final String[] mOneLiners;
private Handler mHandler;
+ private HandlerThread mSenderThread;
+ private Thread mReceiverThread;
private final class ReplyHandler extends Handler {
private StringBuilder mInputSoFar;
@@ -110,8 +112,9 @@
Log.i(LOG_TAG, "Starting RTT chatbot.");
HandlerThread ht = new HandlerThread("RttChatbotSender");
ht.start();
+ mSenderThread = ht;
mHandler = new ReplyHandler(ht.getLooper());
- Thread receiveThread = new Thread(() -> {
+ mReceiverThread = new Thread(() -> {
while (true) {
String charsReceived = mRttTextStream.read();
if (charsReceived == null) {
@@ -129,6 +132,15 @@
.sendToTarget();
}
}, "RttChatbotReceiver");
- receiveThread.start();
+ mReceiverThread.start();
+ }
+
+ public void stop() {
+ if (mSenderThread != null && mSenderThread.isAlive()) {
+ mSenderThread.quit();
+ }
+ if (mReceiverThread != null && mReceiverThread.isAlive()) {
+ mReceiverThread.interrupt();
+ }
}
}
diff --git a/testapps/src/com/android/server/telecom/testapps/TestCallActivity.java b/testapps/src/com/android/server/telecom/testapps/TestCallActivity.java
index 76f2058..ae606c8 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestCallActivity.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestCallActivity.java
@@ -55,6 +55,9 @@
static final String ACTION_RTT_CALL =
"android.telecom.testapps.ACTION_RTT_CALL";
+ public static final String ACTION_REMOTE_RTT_UPGRADE =
+ "android.telecom.testapps.ACTION_REMOTE_RTT_UPGRADE";
+
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -73,6 +76,8 @@
this, data, VideoProfile.STATE_AUDIO_ONLY);
} else if (ACTION_SEND_UPGRADE_REQUEST.equals(action)) {
CallNotificationReceiver.sendUpgradeRequest(this, data);
+ } else if (ACTION_REMOTE_RTT_UPGRADE.equals(action)) {
+ CallNotificationReceiver.remoteRttUpgrade(this);
} else {
CallServiceNotifier.getInstance().updateNotification(this);
}
diff --git a/testapps/src/com/android/server/telecom/testapps/TestCallList.java b/testapps/src/com/android/server/telecom/testapps/TestCallList.java
index 4419b17..1b32690 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestCallList.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestCallList.java
@@ -16,6 +16,7 @@
package com.android.server.telecom.testapps;
+import android.content.Context;
import android.telecom.Call;
import android.telecom.InCallService;
import android.telecom.VideoProfile;
@@ -23,6 +24,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import android.widget.Toast;
import java.util.LinkedList;
import java.util.List;
@@ -37,6 +39,10 @@
public static abstract class Listener {
public void onCallAdded(Call call) {}
public void onCallRemoved(Call call) {}
+ public void onRttStarted(Call call) {}
+ public void onRttStopped(Call call) {}
+ public void onRttInitiationFailed(Call call, int reason) {}
+ public void onRttRequest(Call call, int id) {}
}
private static final TestCallList INSTANCE = new TestCallList();
@@ -97,6 +103,8 @@
private Map<Call, TestVideoCallListener> mVideoCallListeners =
new ArrayMap<Call, TestVideoCallListener>();
private Set<Listener> mListeners = new ArraySet<Listener>();
+ private Context mContext;
+ private int mLastRttRequestId = -1;
/**
* Singleton accessor.
@@ -164,6 +172,10 @@
return mCalls.size();
}
+ public int getLastRttRequestId() {
+ return mLastRttRequestId;
+ }
+
/**
* For any video calls tracked, sends an upgrade to video request.
*/
@@ -218,11 +230,29 @@
@Override
public void onRttStatusChanged(Call call, boolean enabled, Call.RttCall rttCall) {
Log.v(TAG, "onRttStatusChanged: call = " + call + " " + System.identityHashCode(this));
+ if (enabled) {
+ for (Listener l : mListeners) {
+ l.onRttStarted(call);
+ }
+ } else {
+ for (Listener l : mListeners) {
+ l.onRttStopped(call);
+ }
+ }
+ }
- if (call != null) {
- // Did you have another call? Well too bad, this class isn't gonna handle it.
- mCalls.clear();
- mCalls.add(call);
+ @Override
+ public void onRttInitiationFailure(Call call, int reason) {
+ for (Listener l : mListeners) {
+ l.onRttInitiationFailed(call, reason);
+ }
+ }
+
+ @Override
+ public void onRttRequest(Call call, int id) {
+ mLastRttRequestId = id;
+ for (Listener l : mListeners) {
+ l.onRttRequest(call, id);
}
}
}
diff --git a/testapps/src/com/android/server/telecom/testapps/TestConnectionManager.java b/testapps/src/com/android/server/telecom/testapps/TestConnectionManager.java
index c2d8852..abb9108 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestConnectionManager.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestConnectionManager.java
@@ -124,6 +124,26 @@
}
setConferenceableConnections(c);
}
+
+ @Override
+ public void onRttInitiationSuccess(RemoteConnection connection) {
+ sendRttInitiationSuccess();
+ }
+
+ @Override
+ public void onRttInitiationFailure(RemoteConnection connection, int reason) {
+ sendRttInitiationFailure(reason);
+ }
+
+ @Override
+ public void onRttSessionRemotelyTerminated(RemoteConnection connection) {
+ sendRttSessionRemotelyTerminated();
+ }
+
+ @Override
+ public void onRemoteRttRequest(RemoteConnection connection) {
+ sendRemoteRttRequest();
+ }
};
private final RemoteConnection mRemote;
@@ -143,13 +163,17 @@
mRemote.abort();
}
- /** ${inheritDoc} */
+ /**
+ * ${inheritDoc}
+ */
@Override
public void onAnswer(int videoState) {
mRemote.answer(videoState);
}
- /** ${inheritDoc} */
+ /**
+ * ${inheritDoc}
+ */
@Override
public void onDisconnect() {
mRemote.disconnect();
@@ -160,19 +184,25 @@
mRemote.playDtmfTone(c);
}
- /** ${inheritDoc} */
+ /**
+ * ${inheritDoc}
+ */
@Override
public void onHold() {
mRemote.hold();
}
- /** ${inheritDoc} */
+ /**
+ * ${inheritDoc}
+ */
@Override
public void onReject() {
mRemote.reject();
}
- /** ${inheritDoc} */
+ /**
+ * ${inheritDoc}
+ */
@Override
public void onUnhold() {
mRemote.unhold();
@@ -183,6 +213,21 @@
mRemote.setCallAudioState(state);
}
+ @Override
+ public void onStartRtt(RttTextStream rttTextStream) {
+ mRemote.startRtt(rttTextStream);
+ }
+
+ @Override
+ public void onStopRtt() {
+ mRemote.stopRtt();
+ }
+
+ @Override
+ public void handleRttUpgradeResponse(RttTextStream rttTextStream) {
+ mRemote.sendRttUpgradeResponse(rttTextStream);
+ }
+
private void setState(int state) {
log("setState: " + state);
switch (state) {
@@ -201,7 +246,6 @@
}
}
}
-
public final class TestManagedConference extends Conference {
private final RemoteConference.Callback mRemoteCallback = new RemoteConference.Callback() {
@Override
diff --git a/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java b/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
index 6c07073..71af9a8 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
@@ -25,7 +25,6 @@
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;
@@ -39,8 +38,6 @@
import android.telecom.Log;
import android.widget.Toast;
-import com.android.server.telecom.testapps.R;
-
import java.lang.String;
import java.util.ArrayList;
import java.util.List;
@@ -135,6 +132,8 @@
/** Used to cleanup camera and media when done with connection. */
private TestVideoProvider mTestVideoCallProvider;
+ private ConnectionRequest mOriginalRequest;
+ private RttChatbot mRttChatbot;
private BroadcastReceiver mHangupReceiver = new BroadcastReceiver() {
@Override
@@ -154,8 +153,16 @@
}
};
- TestConnection(boolean isIncoming) {
+ private BroadcastReceiver mRttUpgradeReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ sendRemoteRttRequest();
+ }
+ };
+
+ TestConnection(boolean isIncoming, ConnectionRequest request) {
mIsIncoming = isIncoming;
+ mOriginalRequest = request;
// Assume all calls are video capable.
int capabilities = getConnectionCapabilities();
capabilities |= CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL;
@@ -167,6 +174,12 @@
capabilities |= CAPABILITY_RESPOND_VIA_TEXT;
setConnectionCapabilities(capabilities);
+ int properties = getConnectionProperties();
+ if (mOriginalRequest.isRequestingRtt()) {
+ properties |= PROPERTY_IS_RTT;
+ }
+ setConnectionProperties(properties);
+
if (isIncoming) {
putExtra(Connection.EXTRA_ANSWERING_DROPS_FG_CALL, true);
}
@@ -177,17 +190,24 @@
filter.addDataScheme("int");
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(
mUpgradeRequestReceiver, filter);
+
+ LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(
+ mRttUpgradeReceiver,
+ new IntentFilter(TestCallActivity.ACTION_REMOTE_RTT_UPGRADE));
}
void startOutgoing() {
setDialing();
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- setActive();
- activateCall(TestConnection.this);
- }
+ mHandler.postDelayed(() -> {
+ setActive();
+ activateCall(TestConnection.this);
}, 4000);
+ if (mOriginalRequest.isRequestingRtt()) {
+ Log.i(LOG_TAG, "Is RTT call. Starting chatbot service.");
+ mRttChatbot = new RttChatbot(getApplicationContext(),
+ mOriginalRequest.getRttTextStream());
+ mRttChatbot.start();
+ }
}
/** ${inheritDoc} */
@@ -204,6 +224,12 @@
activateCall(this);
setActive();
updateConferenceable();
+ if (mOriginalRequest.isRequestingRtt()) {
+ Log.i(LOG_TAG, "Is RTT call. Starting chatbot service.");
+ mRttChatbot = new RttChatbot(getApplicationContext(),
+ mOriginalRequest.getRttTextStream());
+ mRttChatbot.start();
+ }
}
/** ${inheritDoc} */
@@ -246,6 +272,39 @@
setActive();
}
+ @Override
+ public void onStopRtt() {
+ int newProperties = getConnectionProperties() & ~PROPERTY_IS_RTT;
+ setConnectionProperties(newProperties);
+ mRttChatbot.stop();
+ mRttChatbot = null;
+ }
+
+ @Override
+ public void handleRttUpgradeResponse(RttTextStream rttTextStream) {
+ Log.i(this, "RTT request response was %s", rttTextStream == null);
+ if (rttTextStream != null) {
+ mRttChatbot = new RttChatbot(getApplicationContext(), rttTextStream);
+ mRttChatbot.start();
+ setConnectionProperties(getConnectionProperties() | PROPERTY_IS_RTT);
+ sendRttInitiationSuccess();
+ }
+ }
+
+ @Override
+ public void onStartRtt(RttTextStream textStream) {
+ boolean doAccept = Math.random() < 0.5;
+ if (doAccept) {
+ Log.i(this, "Accepting RTT request.");
+ mRttChatbot = new RttChatbot(getApplicationContext(), textStream);
+ mRttChatbot.start();
+ setConnectionProperties(getConnectionProperties() | PROPERTY_IS_RTT);
+ sendRttInitiationSuccess();
+ } else {
+ sendRttInitiationFailure(RttModifyStatus.SESSION_MODIFY_REQUEST_FAIL);
+ }
+ }
+
public void setTestVideoCallProvider(TestVideoProvider testVideoCallProvider) {
mTestVideoCallProvider = testVideoCallProvider;
}
@@ -273,8 +332,6 @@
/** 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) {
@@ -313,22 +370,12 @@
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 */);
+ final TestConnection connection =
+ new TestConnection(false /* isIncoming */, originalRequest);
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.
@@ -364,7 +411,7 @@
ComponentName componentName = new ComponentName(this, TestConnectionService.class);
if (accountHandle != null && componentName.equals(accountHandle.getComponentName())) {
- final TestConnection connection = new TestConnection(true);
+ final TestConnection connection = new TestConnection(true, request);
// Get the stashed intent extra that determines if this is a video call or audio call.
Bundle extras = request.getExtras();
int videoState = extras.getInt(EXTRA_START_VIDEO_STATE, VideoProfile.STATE_AUDIO_ONLY);
@@ -393,12 +440,6 @@
"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);
@@ -421,7 +462,7 @@
PhoneAccountHandle accountHandle = request.getAccountHandle();
ComponentName componentName = new ComponentName(this, TestConnectionService.class);
if (accountHandle != null && componentName.equals(accountHandle.getComponentName())) {
- final TestConnection connection = new TestConnection(false);
+ final TestConnection connection = new TestConnection(false, request);
final Bundle extras = request.getExtras();
final Uri providedHandle = extras.getParcelable(EXTRA_HANDLE);
diff --git a/testapps/src/com/android/server/telecom/testapps/TestInCallUI.java b/testapps/src/com/android/server/telecom/testapps/TestInCallUI.java
index 809036c..2920ca7 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestInCallUI.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestInCallUI.java
@@ -25,6 +25,7 @@
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ListView;
+import android.widget.Toast;
public class TestInCallUI extends Activity {
@@ -51,6 +52,28 @@
finish();
}
}
+
+ @Override
+ public void onRttStarted(Call call) {
+ Toast.makeText(TestInCallUI.this, "RTT now enabled", Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
+ public void onRttStopped(Call call) {
+ Toast.makeText(TestInCallUI.this, "RTT now disabled", Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
+ public void onRttInitiationFailed(Call call, int reason) {
+ Toast.makeText(TestInCallUI.this, String.format("RTT failed to init: %d", reason),
+ Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
+ public void onRttRequest(Call call, int id) {
+ Toast.makeText(TestInCallUI.this, String.format("RTT request: %d", id),
+ Toast.LENGTH_SHORT).show();
+ }
});
View endCallButton = findViewById(R.id.end_call_button);
@@ -58,6 +81,8 @@
View muteButton = findViewById(R.id.mute_button);
View rttIfaceButton = findViewById(R.id.rtt_iface_button);
View answerButton = findViewById(R.id.answer_button);
+ View startRttButton = findViewById(R.id.start_rtt_button);
+ View acceptRttButton = findViewById(R.id.accept_rtt_button);
endCallButton.setOnClickListener(new OnClickListener() {
@Override
@@ -90,6 +115,7 @@
}
}
});
+
rttIfaceButton.setOnClickListener((view) -> {
Call call = mCallList.getCall(0);
if (call.isRttActive()) {
@@ -98,12 +124,27 @@
startActivity(intent);
}
});
+
answerButton.setOnClickListener(view -> {
Call call = mCallList.getCall(0);
if (call.getState() == Call.STATE_RINGING) {
call.answer(VideoProfile.STATE_AUDIO_ONLY);
}
});
+
+ startRttButton.setOnClickListener(view -> {
+ Call call = mCallList.getCall(0);
+ if (!call.isRttActive()) {
+ call.sendRttRequest();
+ }
+ });
+
+ acceptRttButton.setOnClickListener(view -> {
+ Call call = mCallList.getCall(0);
+ if (!call.isRttActive()) {
+ call.respondToRttRequest(mCallList.getLastRttRequestId(), true);
+ }
+ });
}
/** ${inheritDoc} */
diff --git a/testapps/src/com/android/server/telecom/testapps/TestRttActivity.java b/testapps/src/com/android/server/telecom/testapps/TestRttActivity.java
index ce962b4..9bb6977 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestRttActivity.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestRttActivity.java
@@ -32,6 +32,7 @@
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
+import android.widget.Toast;
import java.io.IOException;
import java.io.InputStreamReader;
@@ -146,6 +147,11 @@
finish();
}
}
+
+ @Override
+ public void onRttStopped(Call call) {
+ TestRttActivity.this.finish();
+ }
});
endRttButton.setOnClickListener((view) -> {
diff --git a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
index 9907ca7..77bf21d 100644
--- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
@@ -30,6 +30,7 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.IInterface;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.telecom.CallAudioState;
import android.telecom.Conference;
@@ -328,6 +329,23 @@
}
@Override
+ public void startRtt(String callId, ParcelFileDescriptor fromInCall,
+ ParcelFileDescriptor toInCall, Session.Info sessionInfo) throws RemoteException {
+
+ }
+
+ @Override
+ public void stopRtt(String callId, Session.Info sessionInfo) throws RemoteException {
+
+ }
+
+ @Override
+ public void respondToRttUpgradeRequest(String callId, ParcelFileDescriptor fromInCall,
+ ParcelFileDescriptor toInCall, Session.Info sessionInfo) throws RemoteException {
+
+ }
+
+ @Override
public IBinder asBinder() {
return this;
}
diff --git a/tests/src/com/android/server/telecom/tests/InCallServiceFixture.java b/tests/src/com/android/server/telecom/tests/InCallServiceFixture.java
index 00760fe..7635427 100644
--- a/tests/src/com/android/server/telecom/tests/InCallServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/InCallServiceFixture.java
@@ -125,6 +125,10 @@
}
@Override
+ public void onRttInitiationFailure(String callId, int reason) throws RemoteException {
+ }
+
+ @Override
public IBinder asBinder() {
return this;
}