Merge "Introduce APIs for RTT calls (part 1)"

am: 27ad05169e

Change-Id: I3fb3cb89b467e5df808967dcd478964a84e2e61f
This commit is contained in:
Hall Liu
2017-02-22 18:56:48 +00:00
committed by android-build-merger
17 changed files with 817 additions and 10 deletions

View File

@@ -36581,9 +36581,11 @@ package android.telecom {
method public android.telecom.Call.Details getDetails();
method public android.telecom.Call getParent();
method public java.lang.String getRemainingPostDialSequence();
method public android.telecom.Call.RttCall getRttCall();
method public int getState();
method public android.telecom.InCallService.VideoCall getVideoCall();
method public void hold();
method public boolean isRttActive();
method public void mergeConference();
method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
method public void playDtmfTone(char);
@@ -36595,9 +36597,12 @@ package android.telecom {
method public void reject(boolean, java.lang.String);
method public final void removeExtras(java.util.List<java.lang.String>);
method public final void removeExtras(java.lang.String...);
method public void respondToRttRequest(int, boolean);
method public void sendCallEvent(java.lang.String, android.os.Bundle);
method public void sendRttRequest();
method public void splitFromConference();
method public void stopDtmfTone();
method public void stopRtt();
method public void swapConference();
method public void unhold();
method public void unregisterCallback(android.telecom.Call.Callback);
@@ -36624,6 +36629,9 @@ package android.telecom {
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
method public void onRttModeChanged(android.telecom.Call, int);
method public void onRttRequest(android.telecom.Call, int);
method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
method public void onStateChanged(android.telecom.Call, int);
method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
}
@@ -36677,6 +36685,19 @@ package android.telecom {
field public static final int PROPERTY_WIFI = 8; // 0x8
}
public static final class Call.RttCall {
method public int getRttAudioMode();
method public java.lang.String read();
method public void setRttMode(int);
method public void write(java.lang.String) throws java.io.IOException;
field public static final int RTT_MODE_FULL = 1; // 0x1
field public static final int RTT_MODE_HCO = 2; // 0x2
field public static final int RTT_MODE_VCO = 3; // 0x3
}
public static abstract class Call.RttCall.RttAudioMode implements java.lang.annotation.Annotation {
}
public final class CallAudioState implements android.os.Parcelable {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
@@ -37048,6 +37069,7 @@ package android.telecom {
field public static final int CAPABILITY_CALL_SUBJECT = 64; // 0x40
field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
field public static final int CAPABILITY_RTT = 4096; // 0x1000
field public static final int CAPABILITY_SELF_MANAGED = 2048; // 0x800
field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400
@@ -37260,6 +37282,7 @@ package android.telecom {
field public static final java.lang.String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
field public static final java.lang.String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";

View File

@@ -39548,9 +39548,11 @@ package android.telecom {
method public android.telecom.Call.Details getDetails();
method public android.telecom.Call getParent();
method public java.lang.String getRemainingPostDialSequence();
method public android.telecom.Call.RttCall getRttCall();
method public int getState();
method public android.telecom.InCallService.VideoCall getVideoCall();
method public void hold();
method public boolean isRttActive();
method public void mergeConference();
method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
method public void playDtmfTone(char);
@@ -39563,9 +39565,12 @@ package android.telecom {
method public final void removeExtras(java.util.List<java.lang.String>);
method public final void removeExtras(java.lang.String...);
method public deprecated void removeListener(android.telecom.Call.Listener);
method public void respondToRttRequest(int, boolean);
method public void sendCallEvent(java.lang.String, android.os.Bundle);
method public void sendRttRequest();
method public void splitFromConference();
method public void stopDtmfTone();
method public void stopRtt();
method public void swapConference();
method public void unhold();
method public void unregisterCallback(android.telecom.Call.Callback);
@@ -39593,6 +39598,9 @@ package android.telecom {
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
method public void onRttModeChanged(android.telecom.Call, int);
method public void onRttRequest(android.telecom.Call, int);
method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
method public void onStateChanged(android.telecom.Call, int);
method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
}
@@ -39650,6 +39658,19 @@ package android.telecom {
ctor public Call.Listener();
}
public static final class Call.RttCall {
method public int getRttAudioMode();
method public java.lang.String read();
method public void setRttMode(int);
method public void write(java.lang.String) throws java.io.IOException;
field public static final int RTT_MODE_FULL = 1; // 0x1
field public static final int RTT_MODE_HCO = 2; // 0x2
field public static final int RTT_MODE_VCO = 3; // 0x3
}
public static abstract class Call.RttCall.RttAudioMode implements java.lang.annotation.Annotation {
}
public final class CallAudioState implements android.os.Parcelable {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
@@ -40152,6 +40173,7 @@ package android.telecom {
field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
field public static final int CAPABILITY_MULTI_USER = 32; // 0x20
field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
field public static final int CAPABILITY_RTT = 4096; // 0x1000
field public static final int CAPABILITY_SELF_MANAGED = 2048; // 0x800
field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400
@@ -40428,6 +40450,7 @@ package android.telecom {
field public static final java.lang.String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
field public static final java.lang.String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";

View File

@@ -36664,9 +36664,11 @@ package android.telecom {
method public android.telecom.Call.Details getDetails();
method public android.telecom.Call getParent();
method public java.lang.String getRemainingPostDialSequence();
method public android.telecom.Call.RttCall getRttCall();
method public int getState();
method public android.telecom.InCallService.VideoCall getVideoCall();
method public void hold();
method public boolean isRttActive();
method public void mergeConference();
method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
method public void playDtmfTone(char);
@@ -36678,9 +36680,12 @@ package android.telecom {
method public void reject(boolean, java.lang.String);
method public final void removeExtras(java.util.List<java.lang.String>);
method public final void removeExtras(java.lang.String...);
method public void respondToRttRequest(int, boolean);
method public void sendCallEvent(java.lang.String, android.os.Bundle);
method public void sendRttRequest();
method public void splitFromConference();
method public void stopDtmfTone();
method public void stopRtt();
method public void swapConference();
method public void unhold();
method public void unregisterCallback(android.telecom.Call.Callback);
@@ -36707,6 +36712,9 @@ package android.telecom {
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
method public void onRttModeChanged(android.telecom.Call, int);
method public void onRttRequest(android.telecom.Call, int);
method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
method public void onStateChanged(android.telecom.Call, int);
method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
}
@@ -36760,6 +36768,19 @@ package android.telecom {
field public static final int PROPERTY_WIFI = 8; // 0x8
}
public static final class Call.RttCall {
method public int getRttAudioMode();
method public java.lang.String read();
method public void setRttMode(int);
method public void write(java.lang.String) throws java.io.IOException;
field public static final int RTT_MODE_FULL = 1; // 0x1
field public static final int RTT_MODE_HCO = 2; // 0x2
field public static final int RTT_MODE_VCO = 3; // 0x3
}
public static abstract class Call.RttCall.RttAudioMode implements java.lang.annotation.Annotation {
}
public final class CallAudioState implements android.os.Parcelable {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
@@ -37131,6 +37152,7 @@ package android.telecom {
field public static final int CAPABILITY_CALL_SUBJECT = 64; // 0x40
field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
field public static final int CAPABILITY_RTT = 4096; // 0x1000
field public static final int CAPABILITY_SELF_MANAGED = 2048; // 0x800
field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400
@@ -37343,6 +37365,7 @@ package android.telecom {
field public static final java.lang.String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
field public static final java.lang.String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";

View File

@@ -16,12 +16,21 @@
package android.telecom;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.ParcelFileDescriptor;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.lang.String;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -828,6 +837,142 @@ public final class Call {
* @param extras Extras associated with the connection event.
*/
public void onConnectionEvent(Call call, String event, Bundle extras) {}
/**
* Invoked when the RTT mode changes for this call.
* @param call The call whose RTT mode has changed.
* @param mode the new RTT mode, one of
* {@link RttCall#RTT_MODE_FULL}, {@link RttCall#RTT_MODE_HCO},
* or {@link RttCall#RTT_MODE_VCO}
*/
public void onRttModeChanged(Call call, int mode) {}
/**
* Invoked when the call's RTT status changes, either from off to on or from on to off.
* @param call The call whose RTT status has changed.
* @param enabled whether RTT is now enabled or disabled
* @param rttCall the {@link RttCall} object to use for reading and writing if RTT is now
* on, null otherwise.
*/
public void onRttStatusChanged(Call call, boolean enabled, RttCall rttCall) {}
/**
* Invoked when the remote end of the connection has requested that an RTT communication
* channel be opened. A response to this should be sent via {@link #respondToRttRequest}
* with the same ID that this method is invoked with.
* @param call The call which the RTT request was placed on
* @param id The ID of the request.
*/
public void onRttRequest(Call call, int id) {}
}
/**
* A class that holds the state that describes the state of the RTT channel to the remote
* party, if it is active.
*/
public static final class RttCall {
@Retention(RetentionPolicy.SOURCE)
@IntDef({RTT_MODE_INVALID, RTT_MODE_FULL, RTT_MODE_HCO, RTT_MODE_VCO})
public @interface RttAudioMode {}
/**
* For metrics use. Default value in the proto.
* @hide
*/
public static final int RTT_MODE_INVALID = 0;
/**
* Indicates that there should be a bidirectional audio stream between the two parties
* on the call.
*/
public static final int RTT_MODE_FULL = 1;
/**
* Indicates that the local user should be able to hear the audio stream from the remote
* user, but not vice versa. Equivalent to muting the microphone.
*/
public static final int RTT_MODE_HCO = 2;
/**
* Indicates that the remote user should be able to hear the audio stream from the local
* user, but not vice versa. Equivalent to setting the volume to zero.
*/
public static final int RTT_MODE_VCO = 3;
private static final int READ_BUFFER_SIZE = 1000;
private InputStreamReader mReceiveStream;
private OutputStreamWriter mTransmitStream;
private int mRttMode;
private final InCallAdapter mInCallAdapter;
private char[] mReadBuffer = new char[READ_BUFFER_SIZE];
/**
* @hide
*/
public RttCall(InputStreamReader receiveStream, OutputStreamWriter transmitStream,
int mode, InCallAdapter inCallAdapter) {
mReceiveStream = receiveStream;
mTransmitStream = transmitStream;
mRttMode = mode;
mInCallAdapter = inCallAdapter;
}
/**
* Returns the current RTT audio mode.
* @return Current RTT audio mode. One of {@link #RTT_MODE_FULL}, {@link #RTT_MODE_VCO}, or
* {@link #RTT_MODE_HCO}.
*/
public int getRttAudioMode() {
return mRttMode;
}
/**
* Sets the RTT audio mode. The requested mode change will be communicated through
* {@link Callback#onRttModeChanged(Call, int)}.
* @param mode The desired RTT audio mode, one of {@link #RTT_MODE_FULL},
* {@link #RTT_MODE_VCO}, or {@link #RTT_MODE_HCO}.
*/
public void setRttMode(@RttAudioMode int mode) {
mInCallAdapter.setRttMode(mode);
}
/**
* Writes the string {@param input} into the outgoing text stream for this RTT call. Since
* RTT transmits text in real-time, this method should be called once for each character
* the user enters into the device.
*
* This method is not thread-safe -- calling it from multiple threads simultaneously may
* lead to interleaved text.
* @param input The message to send to the remote user.
*/
public void write(String input) throws IOException {
mTransmitStream.write(input);
mTransmitStream.flush();
}
/**
* Reads a string from the remote user, blocking if there is no data available. Returns
* {@code null} if the RTT conversation has been terminated and there is no further data
* to read.
*
* This method is not thread-safe -- calling it from multiple threads simultaneously may
* lead to interleaved text.
* @return A string containing text sent by the remote user, or {@code null} if the
* conversation has been terminated or if there was an error while reading.
*/
public String read() {
try {
int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE);
if (numRead < 0) {
return null;
}
return new String(mReadBuffer, 0, numRead);
} catch (IOException e) {
Log.w(this, "Exception encountered when reading from InputStreamReader: %s", e);
return null;
}
}
}
/**
@@ -856,6 +1001,7 @@ public final class Call {
private String mCallingPackage;
private String mRemainingPostDialSequence;
private VideoCallImpl mVideoCallImpl;
private RttCall mRttCall;
private Details mDetails;
private Bundle mExtras;
@@ -1053,6 +1199,34 @@ public final class Call {
mInCallAdapter.sendCallEvent(mTelecomCallId, event, extras);
}
/**
* Sends an RTT upgrade request to the remote end of the connection. Success is not
* guaranteed, and notification of success will be via the
* {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
*/
public void sendRttRequest() {
mInCallAdapter.sendRttRequest();
}
/**
* Responds to an RTT request received via the {@link Callback#onRttRequest(Call, int)} )}
* callback.
* The ID used here should be the same as the ID that was received via the callback.
* @param id The request ID received via {@link Callback#onRttRequest(Call, int)}
* @param accept {@code true} if the RTT request should be accepted, {@code false} otherwise.
*/
public void respondToRttRequest(int id, boolean accept) {
mInCallAdapter.respondToRttRequest(id, accept);
}
/**
* Terminate the RTT session on this call. The resulting state change will be notified via
* the {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
*/
public void stopRtt() {
mInCallAdapter.stopRtt();
}
/**
* Adds some extras to this {@link Call}. Existing keys are replaced and new ones are
* added.
@@ -1232,6 +1406,23 @@ public final class Call {
return mDetails;
}
/**
* Returns this call's RttCall object. The {@link RttCall} instance is used to send and
* receive RTT text data, as well as to change the RTT mode.
* @return A {@link Call.RttCall}. {@code null} if there is no active RTT connection.
*/
public @Nullable RttCall getRttCall() {
return mRttCall;
}
/**
* Returns whether this call has an active RTT connection.
* @return true if there is a connection, false otherwise.
*/
public boolean isRttActive() {
return mRttCall != null;
}
/**
* Registers a callback to this {@code Call}.
*
@@ -1426,6 +1617,32 @@ public final class Call {
fireConferenceableCallsChanged();
}
boolean isRttChanged = false;
boolean rttModeChanged = false;
if (parcelableCall.getParcelableRttCall() != null && parcelableCall.getIsRttCallChanged()) {
ParcelableRttCall parcelableRttCall = parcelableCall.getParcelableRttCall();
InputStreamReader receiveStream = new InputStreamReader(
new ParcelFileDescriptor.AutoCloseInputStream(
parcelableRttCall.getReceiveStream()),
StandardCharsets.UTF_8);
OutputStreamWriter transmitStream = new OutputStreamWriter(
new ParcelFileDescriptor.AutoCloseOutputStream(
parcelableRttCall.getTransmitStream()),
StandardCharsets.UTF_8);
RttCall newRttCall = new Call.RttCall(
receiveStream, transmitStream, parcelableRttCall.getRttMode(), mInCallAdapter);
if (mRttCall == null) {
isRttChanged = true;
} else if (mRttCall.getRttAudioMode() != newRttCall.getRttAudioMode()) {
rttModeChanged = true;
}
mRttCall = newRttCall;
} else if (mRttCall != null && parcelableCall.getParcelableRttCall() == null
&& parcelableCall.getIsRttCallChanged()) {
isRttChanged = true;
mRttCall = null;
}
// Now we fire updates, ensuring that any client who listens to any of these notifications
// gets the most up-to-date state.
@@ -1447,6 +1664,12 @@ public final class Call {
if (childrenChanged) {
fireChildrenChanged(getChildren());
}
if (isRttChanged) {
fireOnIsRttChanged(mRttCall != null, mRttCall);
}
if (rttModeChanged) {
fireOnRttModeChanged(mRttCall.getRttAudioMode());
}
// If we have transitioned to DISCONNECTED, that means we need to notify clients and
// remove ourselves from the Phone. Note that we do this after completing all state updates
@@ -1477,6 +1700,15 @@ public final class Call {
fireOnConnectionEvent(event, extras);
}
/** {@hide} */
final void internalOnRttUpgradeRequest(final int requestId) {
for (CallbackRecord<Callback> record : mCallbackRecords) {
final Call call = this;
final Callback callback = record.getCallback();
record.getHandler().post(() -> callback.onRttRequest(call, requestId));
}
}
private void fireStateChanged(final int newState) {
for (CallbackRecord<Callback> record : mCallbackRecords) {
final Call call = this;
@@ -1644,6 +1876,32 @@ public final class Call {
}
}
/**
* Notifies listeners of an RTT on/off change
*
* @param enabled True if RTT is now enabled, false otherwise
*/
private void fireOnIsRttChanged(final boolean enabled, final RttCall rttCall) {
for (CallbackRecord<Callback> record : mCallbackRecords) {
final Call call = this;
final Callback callback = record.getCallback();
record.getHandler().post(() -> callback.onRttStatusChanged(call, enabled, rttCall));
}
}
/**
* Notifies listeners of a RTT mode change
*
* @param mode The new RTT mode
*/
private void fireOnRttModeChanged(final int mode) {
for (CallbackRecord<Callback> record : mCallbackRecords) {
final Call call = this;
final Callback callback = record.getCallback();
record.getHandler().post(() -> callback.onRttModeChanged(call, mode));
}
}
/**
* Determines if two bundles are equal.
*

View File

@@ -31,10 +31,14 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.ArraySet;
import android.view.Surface;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -385,8 +389,14 @@ public abstract class Connection extends Conferenceable {
*/
public static final int PROPERTY_SELF_MANAGED = 1<<7;
/**
* When set, indicates that a connection has an active RTT session associated with it.
* @hide
*/
public static final int PROPERTY_IS_RTT = 1 << 8;
//**********************************************************************************************
// Next PROPERTY value: 1<<8
// Next PROPERTY value: 1<<9
//**********************************************************************************************
/**
@@ -756,6 +766,65 @@ public abstract class Connection extends Conferenceable {
public void onAudioRouteChanged(Connection c, int audioRoute) {}
}
/**
* Provides methods to read and write RTT data to/from the in-call app.
* @hide
*/
public static final class RttTextStream {
private static final int READ_BUFFER_SIZE = 1000;
private final InputStreamReader mPipeFromInCall;
private final OutputStreamWriter mPipeToInCall;
private char[] mReadBuffer = new char[READ_BUFFER_SIZE];
/**
* @hide
*/
public RttTextStream(ParcelFileDescriptor toInCall, ParcelFileDescriptor fromInCall) {
mPipeFromInCall = new InputStreamReader(
new ParcelFileDescriptor.AutoCloseInputStream(fromInCall));
mPipeToInCall = new OutputStreamWriter(
new ParcelFileDescriptor.AutoCloseOutputStream(toInCall));
}
/**
* Writes the string {@param input} into the text stream to the UI for this RTT call. Since
* RTT transmits text in real-time, this method should be called as often as text snippets
* are received from the remote user, even if it is only one character.
*
* This method is not thread-safe -- calling it from multiple threads simultaneously may
* lead to interleaved text.
* @param input The message to send to the in-call app.
*/
public void write(String input) throws IOException {
mPipeToInCall.write(input);
mPipeToInCall.flush();
}
/**
* Reads a string from the in-call app, blocking if there is no data available. Returns
* {@code null} if the RTT conversation has been terminated and there is no further data
* to read.
*
* This method is not thread-safe -- calling it from multiple threads simultaneously may
* lead to interleaved text.
* @return A string containing text entered by the user, or {@code null} if the
* conversation has been terminated or if there was an error while reading.
*/
public String read() {
try {
int numRead = mPipeFromInCall.read(mReadBuffer, 0, READ_BUFFER_SIZE);
if (numRead < 0) {
return null;
}
return new String(mReadBuffer, 0, numRead);
} catch (IOException e) {
Log.w(this, "Exception encountered when reading from InputStreamReader: %s", e);
return null;
}
}
}
/**
* Provides a means of controlling the video session associated with a {@link Connection}.
* <p>

View File

@@ -19,6 +19,7 @@ package android.telecom;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
/**
@@ -27,13 +28,121 @@ import android.os.Parcelable;
*/
public final class ConnectionRequest implements Parcelable {
// TODO: Token to limit recursive invocations
/**
* Builder class for {@link ConnectionRequest}
* @hide
*/
public static final class Builder {
private PhoneAccountHandle mAccountHandle;
private Uri mAddress;
private Bundle mExtras;
private int mVideoState = VideoProfile.STATE_AUDIO_ONLY;
private String mTelecomCallId;
private boolean mShouldShowIncomingCallUi = false;
private ParcelFileDescriptor mRttPipeToInCall;
private ParcelFileDescriptor mRttPipeFromInCall;
public Builder() { }
/**
* Sets the phone account handle for the resulting {@link ConnectionRequest}
* @param accountHandle The accountHandle which should be used to place the call.
*/
public Builder setAccountHandle(PhoneAccountHandle accountHandle) {
this.mAccountHandle = accountHandle;
return this;
}
/**
* Sets the address for the resulting {@link ConnectionRequest}
* @param address The address(e.g., phone number) to which the {@link Connection} is to
* connect.
*/
public Builder setAddress(Uri address) {
this.mAddress = address;
return this;
}
/**
* Sets the extras bundle for the resulting {@link ConnectionRequest}
* @param extras Application-specific extra data.
*/
public Builder setExtras(Bundle extras) {
this.mExtras = extras;
return this;
}
/**
* Sets the video state for the resulting {@link ConnectionRequest}
* @param videoState Determines the video state for the connection.
*/
public Builder setVideoState(int videoState) {
this.mVideoState = videoState;
return this;
}
/**
* Sets the Telecom call ID for the resulting {@link ConnectionRequest}
* @param telecomCallId The telecom call ID.
*/
public Builder setTelecomCallId(String telecomCallId) {
this.mTelecomCallId = telecomCallId;
return this;
}
/**
* Sets shouldShowIncomingUi for the resulting {@link ConnectionRequest}
* @param shouldShowIncomingCallUi For a self-managed {@link ConnectionService}, will be
* {@code true} if the {@link ConnectionService} should show
* its own incoming call UI for an incoming call. When
* {@code false}, Telecom shows the incoming call UI.
*/
public Builder setShouldShowIncomingCallUi(boolean shouldShowIncomingCallUi) {
this.mShouldShowIncomingCallUi = shouldShowIncomingCallUi;
return this;
}
/**
* Sets the RTT pipe for transferring text into the {@link ConnectionService} for the
* resulting {@link ConnectionRequest}
* @param rttPipeFromInCall The data pipe to read from.
*/
public Builder setRttPipeFromInCall(ParcelFileDescriptor rttPipeFromInCall) {
this.mRttPipeFromInCall = rttPipeFromInCall;
return this;
}
/**
* Sets the RTT pipe for transferring text out of {@link ConnectionService} for the
* resulting {@link ConnectionRequest}
* @param rttPipeToInCall The data pipe to write to.
*/
public Builder setRttPipeToInCall(ParcelFileDescriptor rttPipeToInCall) {
this.mRttPipeToInCall = rttPipeToInCall;
return this;
}
public ConnectionRequest build() {
return new ConnectionRequest(
mAccountHandle,
mAddress,
mExtras,
mVideoState,
mTelecomCallId,
mShouldShowIncomingCallUi,
mRttPipeFromInCall,
mRttPipeToInCall);
}
}
private final PhoneAccountHandle mAccountHandle;
private final Uri mAddress;
private final Bundle mExtras;
private final int mVideoState;
private final String mTelecomCallId;
private final boolean mShouldShowIncomingCallUi;
private final ParcelFileDescriptor mRttPipeToInCall;
private final ParcelFileDescriptor mRttPipeFromInCall;
/**
* @param accountHandle The accountHandle which should be used to place the call.
@@ -44,7 +153,7 @@ public final class ConnectionRequest implements Parcelable {
PhoneAccountHandle accountHandle,
Uri handle,
Bundle extras) {
this(accountHandle, handle, extras, VideoProfile.STATE_AUDIO_ONLY, null, false);
this(accountHandle, handle, extras, VideoProfile.STATE_AUDIO_ONLY, null, false, null, null);
}
/**
@@ -58,7 +167,7 @@ public final class ConnectionRequest implements Parcelable {
Uri handle,
Bundle extras,
int videoState) {
this(accountHandle, handle, extras, videoState, null, false);
this(accountHandle, handle, extras, videoState, null, false, null, null);
}
/**
@@ -80,12 +189,27 @@ public final class ConnectionRequest implements Parcelable {
int videoState,
String telecomCallId,
boolean shouldShowIncomingCallUi) {
this(accountHandle, handle, extras, videoState, telecomCallId,
shouldShowIncomingCallUi, null, null);
}
private ConnectionRequest(
PhoneAccountHandle accountHandle,
Uri handle,
Bundle extras,
int videoState,
String telecomCallId,
boolean shouldShowIncomingCallUi,
ParcelFileDescriptor rttPipeFromInCall,
ParcelFileDescriptor rttPipeToInCall) {
mAccountHandle = accountHandle;
mAddress = handle;
mExtras = extras;
mVideoState = videoState;
mTelecomCallId = telecomCallId;
mShouldShowIncomingCallUi = shouldShowIncomingCallUi;
mRttPipeFromInCall = rttPipeFromInCall;
mRttPipeToInCall = rttPipeToInCall;
}
private ConnectionRequest(Parcel in) {
@@ -95,6 +219,8 @@ public final class ConnectionRequest implements Parcelable {
mVideoState = in.readInt();
mTelecomCallId = in.readString();
mShouldShowIncomingCallUi = in.readInt() == 1;
mRttPipeFromInCall = in.readParcelable(getClass().getClassLoader());
mRttPipeToInCall = in.readParcelable(getClass().getClassLoader());
}
/**
@@ -149,6 +275,59 @@ public final class ConnectionRequest implements Parcelable {
return mShouldShowIncomingCallUi;
}
/**
* Gets the {@link ParcelFileDescriptor} that is used to send RTT text from the connection
* service to the in-call UI. In order to obtain an
* {@link java.io.InputStream} from this {@link ParcelFileDescriptor}, use
* {@link android.os.ParcelFileDescriptor.AutoCloseInputStream}.
* Only text data encoded using UTF-8 should be written into this {@link ParcelFileDescriptor}.
* @return The {@link ParcelFileDescriptor} that should be used for communication.
* Do not un-hide -- only for use by Telephony
* @hide
*/
public ParcelFileDescriptor getRttPipeToInCall() {
return mRttPipeToInCall;
}
/**
* Gets the {@link ParcelFileDescriptor} that is used to send RTT text from the in-call UI to
* the connection service. In order to obtain an
* {@link java.io.OutputStream} from this {@link ParcelFileDescriptor}, use
* {@link android.os.ParcelFileDescriptor.AutoCloseOutputStream}.
* The contents of this {@link ParcelFileDescriptor} will consist solely of text encoded in
* UTF-8.
* @return The {@link ParcelFileDescriptor} that should be used for communication
* Do not un-hide -- only for use by Telephony
* @hide
*/
public ParcelFileDescriptor getRttPipeFromInCall() {
return mRttPipeFromInCall;
}
/**
* Gets the {@link android.telecom.Connection.RttTextStream} object that should be used to
* send and receive RTT text to/from the in-call app.
* @return An instance of {@link android.telecom.Connection.RttTextStream}, or {@code null}
* if this connection request is not requesting an RTT session upon connection establishment.
* @hide
*/
public Connection.RttTextStream getRttTextStream() {
if (isRequestingRtt()) {
return new Connection.RttTextStream(mRttPipeToInCall, mRttPipeFromInCall);
} else {
return null;
}
}
/**
* Convenience method for determining whether the ConnectionRequest is requesting an RTT session
* @return {@code true} if RTT is requested, {@code false} otherwise.
* @hide
*/
public boolean isRequestingRtt() {
return mRttPipeFromInCall != null && mRttPipeToInCall != null;
}
@Override
public String toString() {
return String.format("ConnectionRequest %s %s",
@@ -186,5 +365,7 @@ public final class ConnectionRequest implements Parcelable {
destination.writeInt(mVideoState);
destination.writeString(mTelecomCallId);
destination.writeInt(mShouldShowIncomingCallUi ? 1 : 0);
destination.writeParcelable(mRttPipeFromInCall, 0);
destination.writeParcelable(mRttPipeToInCall, 0);
}
}

View File

@@ -34,7 +34,7 @@ import java.util.List;
* <p>
* The adapter will stop functioning when there are no more calls.
*
* {@hide}
* @hide
*/
public final class InCallAdapter {
private final IInCallAdapter mAdapter;
@@ -375,4 +375,48 @@ public final class InCallAdapter {
} catch (RemoteException ignored) {
}
}
/**
* Sends an RTT upgrade request to the remote end of the connection.
*/
public void sendRttRequest() {
try {
mAdapter.sendRttRequest();
} catch (RemoteException ignored) {
}
}
/**
* Responds to an RTT upgrade request initiated from the remote end.
*
* @param id the ID of the request as specified by Telecom
* @param accept Whether the request should be accepted.
*/
public void respondToRttRequest(int id, boolean accept) {
try {
mAdapter.respondToRttRequest(id, accept);
} catch (RemoteException ignored) {
}
}
/**
* Instructs Telecom to shut down the RTT communication channel.
*/
public void stopRtt() {
try {
mAdapter.stopRtt();
} catch (RemoteException ignored) {
}
}
/**
* Sets the RTT audio mode.
* @param mode the desired RTT audio mode
*/
public void setRttMode(int mode) {
try {
mAdapter.setRttMode(mode);
} catch (RemoteException ignored) {
}
}
}

View File

@@ -76,6 +76,7 @@ public abstract class InCallService extends Service {
private static final int MSG_ON_CAN_ADD_CALL_CHANGED = 7;
private static final int MSG_SILENCE_RINGER = 8;
private static final int MSG_ON_CONNECTION_EVENT = 9;
private static final int MSG_ON_RTT_UPGRADE_REQUEST = 10;
/** Default Handler used to consolidate binder method calls onto a single thread. */
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -133,6 +134,12 @@ public abstract class InCallService extends Service {
}
break;
}
case MSG_ON_RTT_UPGRADE_REQUEST: {
String callId = (String) msg.obj;
int requestId = msg.arg1;
mPhone.internalOnRttUpgradeRequest(callId, requestId);
break;
}
default:
break;
}
@@ -198,6 +205,11 @@ public abstract class InCallService extends Service {
args.arg3 = extras;
mHandler.obtainMessage(MSG_ON_CONNECTION_EVENT, args).sendToTarget();
}
@Override
public void onRttUpgradeRequest(String callId, int id) {
mHandler.obtainMessage(MSG_ON_RTT_UPGRADE_REQUEST, id, 0, callId).sendToTarget();
}
}
private Phone.Listener mPhoneListener = new Phone.Listener() {

View File

@@ -50,6 +50,8 @@ public final class ParcelableCall implements Parcelable {
private final boolean mIsVideoCallProviderChanged;
private final IVideoProvider mVideoCallProvider;
private VideoCallImpl mVideoCall;
private final boolean mIsRttCallChanged;
private final ParcelableRttCall mRttCall;
private final String mParentCallId;
private final List<String> mChildCallIds;
private final StatusHints mStatusHints;
@@ -75,6 +77,8 @@ public final class ParcelableCall implements Parcelable {
PhoneAccountHandle accountHandle,
boolean isVideoCallProviderChanged,
IVideoProvider videoCallProvider,
boolean isRttCallChanged,
ParcelableRttCall rttCall,
String parentCallId,
List<String> childCallIds,
StatusHints statusHints,
@@ -98,6 +102,8 @@ public final class ParcelableCall implements Parcelable {
mAccountHandle = accountHandle;
mIsVideoCallProviderChanged = isVideoCallProviderChanged;
mVideoCallProvider = videoCallProvider;
mIsRttCallChanged = isRttCallChanged;
mRttCall = rttCall;
mParentCallId = parentCallId;
mChildCallIds = childCallIds;
mStatusHints = statusHints;
@@ -202,6 +208,18 @@ public final class ParcelableCall implements Parcelable {
return mVideoCall;
}
public boolean getIsRttCallChanged() {
return mIsRttCallChanged;
}
/**
* RTT communication channel information
* @return The ParcelableRttCall
*/
public ParcelableRttCall getParcelableRttCall() {
return mRttCall;
}
/**
* The conference call to which this call is conferenced. Null if not conferenced.
*/
@@ -301,6 +319,8 @@ public final class ParcelableCall implements Parcelable {
Bundle intentExtras = source.readBundle(classLoader);
Bundle extras = source.readBundle(classLoader);
int supportedAudioRoutes = source.readInt();
boolean isRttCallChanged = source.readByte() == 1;
ParcelableRttCall rttCall = source.readParcelable(classLoader);
return new ParcelableCall(
id,
state,
@@ -318,6 +338,8 @@ public final class ParcelableCall implements Parcelable {
accountHandle,
isVideoCallProviderChanged,
videoCallProvider,
isRttCallChanged,
rttCall,
parentCallId,
childCallIds,
statusHints,
@@ -366,6 +388,8 @@ public final class ParcelableCall implements Parcelable {
destination.writeBundle(mIntentExtras);
destination.writeBundle(mExtras);
destination.writeInt(mSupportedAudioRoutes);
destination.writeByte((byte) (mIsRttCallChanged ? 1 : 0));
destination.writeParcelable(mRttCall, 0);
}
@Override

View File

@@ -0,0 +1,22 @@
/*
* Copyright 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 android.telecom;
/**
* {@hide}
*/
parcelable ParcelableRttCall;

View File

@@ -0,0 +1,88 @@
/*
* 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 android.telecom;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
/**
* Data container for information associated with the RTT connection on a call.
* @hide
*/
public class ParcelableRttCall implements Parcelable {
private final int mRttMode;
private final ParcelFileDescriptor mTransmitStream;
private final ParcelFileDescriptor mReceiveStream;
public ParcelableRttCall(
int rttMode,
ParcelFileDescriptor transmitStream,
ParcelFileDescriptor receiveStream) {
mRttMode = rttMode;
mTransmitStream = transmitStream;
mReceiveStream = receiveStream;
}
protected ParcelableRttCall(Parcel in) {
mRttMode = in.readInt();
mTransmitStream = in.readParcelable(ParcelFileDescriptor.class.getClassLoader());
mReceiveStream = in.readParcelable(ParcelFileDescriptor.class.getClassLoader());
}
public static final Creator<ParcelableRttCall> CREATOR = new Creator<ParcelableRttCall>() {
@Override
public ParcelableRttCall createFromParcel(Parcel in) {
return new ParcelableRttCall(in);
}
@Override
public ParcelableRttCall[] newArray(int size) {
return new ParcelableRttCall[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mRttMode);
dest.writeParcelable(mTransmitStream, flags);
dest.writeParcelable(mReceiveStream, flags);
}
public int getRttMode() {
return mRttMode;
}
public ParcelFileDescriptor getReceiveStream() {
return mReceiveStream;
}
public ParcelFileDescriptor getTransmitStream() {
return mTransmitStream;
}
}

View File

@@ -201,6 +201,13 @@ public final class Phone {
}
}
final void internalOnRttUpgradeRequest(String callId, int requestId) {
Call call = mCallByTelecomCallId.get(callId);
if (call != null) {
call.internalOnRttUpgradeRequest(requestId);
}
}
/**
* Called to destroy the phone and cleanup any lingering calls.
*/

View File

@@ -203,6 +203,18 @@ public final class PhoneAccount implements Parcelable {
*/
public static final int CAPABILITY_SELF_MANAGED = 0x800;
/**
* Flag indicating that this {@link PhoneAccount} is capable of making a call with an
* RTT (Real-time text) session.
* When set, Telecom will attempt to open an RTT session on outgoing calls that specify
* that they should be placed with an RTT session , and the in-call app will be displayed
* with text entry fields for RTT. Likewise, the in-call app can request that an RTT
* session be opened during a call if this bit is set.
*/
public static final int CAPABILITY_RTT = 0x1000;
/* NEXT CAPABILITY: 0x2000 */
/**
* URI scheme for telephone number URIs.
*/

View File

@@ -450,11 +450,14 @@ final class RemoteConnectionService {
ConnectionRequest request,
boolean isIncoming) {
final String id = UUID.randomUUID().toString();
final ConnectionRequest newRequest = new ConnectionRequest(
request.getAccountHandle(),
request.getAddress(),
request.getExtras(),
request.getVideoState());
final ConnectionRequest newRequest = new ConnectionRequest.Builder()
.setAccountHandle(request.getAccountHandle())
.setAddress(request.getAddress())
.setExtras(request.getExtras())
.setVideoState(request.getVideoState())
.setRttPipeFromInCall(request.getRttPipeFromInCall())
.setRttPipeToInCall(request.getRttPipeToInCall())
.build();
try {
if (mConnectionById.isEmpty()) {
mOutgoingConnectionServiceRpc.addConnectionServiceAdapter(mServant.getStub(),

View File

@@ -325,6 +325,14 @@ public class TelecomManager {
public static final String EXTRA_NEW_OUTGOING_CALL_CANCEL_TIMEOUT =
"android.telecom.extra.NEW_OUTGOING_CALL_CANCEL_TIMEOUT";
/**
* A boolean extra, which when set on the {@link Intent#ACTION_CALL} intent or on the bundle
* passed into {@link #placeCall(Uri, Bundle)}, indicates that the call should be initiated with
* an RTT session open. See {@link android.telecom.Call.RttCall} for more information on RTT.
*/
public static final String EXTRA_START_CALL_WITH_RTT =
"android.telecom.extra.START_CALL_WITH_RTT";
/**
* A boolean meta-data value indicating whether an {@link InCallService} implements an
* in-call user interface. Dialer implementations (see {@link #getDefaultDialerPackage()}) which

View File

@@ -69,4 +69,12 @@ oneway interface IInCallAdapter {
void putExtras(String callId, in Bundle extras);
void removeExtras(String callId, in List<String> keys);
void sendRttRequest();
void respondToRttRequest(int id, boolean accept);
void stopRtt();
void setRttMode(int mode);
}

View File

@@ -50,4 +50,6 @@ oneway interface IInCallService {
void silenceRinger();
void onConnectionEvent(String callId, String event, in Bundle extras);
void onRttUpgradeRequest(String callId, int id);
}